Mongodb检查数组的子文档中是否存在字段

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mongodb检查数组的子文档中是否存在字段相关的知识,希望对你有一定的参考价值。

我正在尝试检查数组的子文档中是否存在字段,如果存在,它将仅在回调中提供那些文档。但是每次我记录回调文档时,它都会为我提供数组中的所有值,而不是基于查询的值。

I am following this tutorial唯一的区别是我使用的是findOne函数而不是find函数,但是它仍然带给我所有值。我尝试使用查找,它做同样的事情。

我也使用与上面的链接中的示例相同的收集样式。

示例enter image description here在上图中,您可以在上图中看到我的文档带有uid字段和contacts数组。我想做的是首先根据输入的uid选择一个文档。然后,在选择该文档之后,我想显示contacts数组中存在[[contacts.uid字段的值。因此,从上图可以看出,只有要显示的值为contacts [0]contacts [3],因为contacts 1没有uid字段。

Contact.contactModel.findOne($and: [ uid: self.uid, contacts: $elemMatch: uid: $exists: true, $ne: undefined, ]
答案
在上面提到的教程中,它们将2个参数传递给方法,一个参数用于过滤器,一个参数用于投影,但是您刚刚传递了一个,这就是区别。您可以将查询更改为:

Contact.contactModel.findOne( uid: self.uid, contacts: $elemMatch: uid: $exists: true, $ne: undefined, )

另一答案
agg框架使对字段存在的筛选有些棘手。我认为OP希望所有子文档中某个字段存在于子文档数组中,然后仅返回该字段存在的那些子文档。以下应该可以解决问题:

var inputtedUID = "0"; // doesn't matter db.foo.aggregate( [ // This $match finds the docs with our input UID: $match: "uid": inputtedUID // ... and the $addFields/$filter will strip out those entries in contacts where contacts.uid does NOT exist. We wish we could use cond: $zz.name: $exists:true but // we cannot use $exists here so we need the convoluted $ifNull treatment. Note we // overwrite the original contacts with the filtered contacts: ,$addFields: contacts: $filter: input: "$contacts", as: "zz", cond: $ne: [ $ifNull:["$$zz.uid",null], null] ,$limit:1 // just get 1 like findOne() ]); show(c); "_id" : 0, "uid" : 0, "contacts" : [ "uid" : "buzz", "n" : 1 , "uid" : "dave", "n" : 2 ]

另一答案
您的问题来自对MongoDB中数据建模的误解,这对来自其他DBMS的开发人员来说并不罕见。让我以RDBMS与MongoDB(以及许多其他NoSQL数据库)如何进行数据建模的示例来说明这一点。

使用RDBMS,您可以识别您的实体及其属性。接下来,您确定关系,对数据模型进行标准化,然后碰壁碰壁,以获得UPPER LEFT ABOVE AND BEYOND JOIN™,它将回答用例A产生的问题。然后,您对用例几乎要做同样的事情B。

使用MongoDB,您可以将其颠倒过来。在查看用例时,您将尝试找出需要哪些信息来回答用例产生的问题,然后对数据进行建模,以便可以最有效的方式回答这些问题。

让我们坚持使用您的联系人数据库示例。这里要做一些假设:

    每个用户可以有任意数量的联系人。
  1. 每个联系人和每个用户都需要用名称以外的其他方式唯一地标识,因为名称可以更改,而不能更改。
  2. 冗余不是一件坏事。
  • 第一个假设是,将联系人嵌入到用户文档中是毫无疑问的,因为存在文档大小限制。关于我们的第二个假设:uid字段变得多余,而变得毫无用处,因为[[is _id字段已经唯一标识了相关数据集。

    用例让我们看一些用例,为便于示例,这些用例已得到简化,但会为您提供图片。

    给用户,我想找到一个联系人。

    1. 给一个用户,我想找到他的所有联系人。
    2. 给一个用户,我想找到他的联系人“ John Doe”的详细信息
    3. 给联系人,我要编辑它。
    4. 给联系人,我要删除它。
  • 数据模型
  • 用户

    "_id": new ObjectId(), "name": new String(), "whatever":

    联系人

    
      "_id": new ObjectId(),
      "contactOf": ObjectId(),
      "name": new String(),
      "phone": new String()
    
    

    显然,contactOf引用必须在User集合中存在的ObjectId。
    实现

    给用户,我想找到一个联系人。
    如果有用户对象,则为_id,并且对单个联系人的查询变得非常简单]

    db.contacts.findOne("contactOf":self._id)

    给一个用户,我想找到他的所有联系人。
    同样容易:

    db.contacts.find("contactOf":self._id)

    给一个用户,我想找到他的联系人“ John Doe”的详细信息
    db.contacts.find("contactOf":self._id,"name":"John Doe")

    现在我们可以采用一种或另一种方式联系,

    包括他/她/不确定/选择不说_id,我们可以轻松地编辑/删除它:

    给联系人,我要编辑它。

    db.contacts.update("_id":contact._id,$set:"name":"John F Doe")

    [我相信,到现在为止,您已经对如何从用户的联系人中删除John有了一个了解。

    注意

    指数

    对于您的数据模型,您需要为uid字段添加其他索引-如我们所知,这毫无用处。此外,_id默认情况下已建立索引,因此我们可以充分利用此索引。应该在contact集合上执行其他索引,但是:

    db.contact.ensureIndex("contactOf":1,"name":1)

    规范化

    这里完全没有做。造成这种情况的原因是多种多样的,但是最重要的是,尽管John Doe可能只有手机号码“ Mallory H Ousefriend”,但他的妻子Jane Doe也可能拥有电子邮件地址“ janes_naughty_boy@censored.com”-该地址为至少,马洛里肯定不想在约翰的联系人列表中弹出。因此,即使我们具有联系人身份,您也很可能不想反映出来。

    结论

    通过少量的数据重构,我们将所需的其他索引数减少到1,使查询变得更加简单,并且规避了BSON文档的大小限制。至于性能,我想我们正在谈论至少一个数量级。

  • 以上是关于Mongodb检查数组的子文档中是否存在字段的主要内容,如果未能解决你的问题,请参考以下文章

    如何匹配 MongoDB 中的子文档数组?

    如何匹配MongoDB中的子文档数组?

    如何在mongodb聚合中检查子字段是不是存在且不为空?

    MongoDB - 无法将时间戳字段添加到数组中的子文档

    在 MongoDB 中,何时使用简单的子文档,何时使用具有 2 字段元素的数组?

    如何检查文档字段类型数组中是不是存在元素?扑