检查数组的子文档中是否存在该字段 [英] Check If field exists in an sub-document of an Array

查看:82
本文介绍了检查数组的子文档中是否存在该字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个与此相似的架构.

I have a schema that is similar to this.

{id: Number,
  line_items: [{ 
    id: String,
    quantity: Number,
    review_request_sent :Boolean
  }],
  total_price: String,
  name: String,
  order_number: Number
}

我要查找的是所有未为数组中所有项目设置字段review_request_sent的文档.

What I want to find is all documents that don't have the field review_request_sent set for all items in the array.

示例

{ 
  id: 1, 
  line_items: [
    {
      id: 43,
      review_request_sent: true
    }
  ]
},
{
  id: 2,
  line_items: [
    {
      id: 1,
      review_request_sent: false
    },
    {
      id: 39
    },
 ]
},
{
  id: 3,
  line_items: [
    {
     id: 23,
     review_request_sent: true
    },
    {
     id: 85,
     review_request_sent: true
    },
    {
     id: 12,
     review_request_sent: false
    }
  ]
}

我希望获得仅返回第二个文档的查询/查找的帮助,因为它在其数组的所有项中都没有review_request_sent字段.

I would want help with a query/find that will return only the second document because it does not have the review_request_sent field in all its items in its array.

推荐答案

您基本上想要 $elemMatch $exists 运算符,因为它将检查每个元素以查看条件"field不存在"对于任何元素是否为真:

You basically want $elemMatch and the $exists operator, as this will inspect each element to see if the condition "field not exists" is true for any element:

Model.find({
  "line_items": {
      "$elemMatch": { "review_request_sent": { "$exists": false } }
  }
},function(err,docs) {

});

仅当该数组子文档之一中不存在该字段时,它才返回第二个文档:

That returns the second document only as the field is not present in one of the array sub-documents:

{
        "id" : 2,
        "line_items" : [
                {
                        "id" : 1,
                        "review_request_sent" : false
                },
                {
                        "id" : 39
                }
        ]
}

请注意,这与以下形式有所不同":

Note that this "differs" from this form:

Model.find({
  "line_items.review_request_sent": { "$exists": false } 
},function(err,docs) {

})

询问的位置数组元素的全部"不包含此字段,当文档中至少有一个存在该字段的元素时,情况并非如此.因此,$eleMatch使条件可以针对每个"数组元素进行测试,从而获得正确的响应.

Where that is asking does "all" of the array elements not contain this field, which is not true when a document has at least one element that has the field present. So the $eleMatch makes the condition be tested against "each" array element, and thus you get the correct response.

如果您想更新此数据,以便找到的任何不包含该字段的数组元素都将接收值为false的该字段(大概是),那么您甚至可以编写如下语句: /p>

If you wanted to update this data so that any array element found that did not contain this field was to then receive that field with a value of false ( presumably ), then you could even write a statement like this:

    Model.aggregate(
      [
        { "$match": { 
          "line_items": {
            "$elemMatch": { "review_request_sent": { "$exists": false } }
          } 
        }},
        { "$project": {
          "line_items": {
            "$setDifference": [
              {"$map": {
                "input": "$line_items",
                "as": "item",
                "in": {
                  "$cond": [
                    { "$eq": [ 
                      { "$ifNull": [ "$$item.review_request_sent", null ] },
                      null
                    ]},
                    "$$item.id",
                    false
                  ]
                }
              }},
              [false]
            ]
          }
        }}
    ],
    function(err,docs) {
      if (err) throw err;
      async.each(
        docs,
        function(doc,callback) {
          async.each(
            doc.line_items,
            function(item,callback) {
              Model.update(
                { "_id": doc._id, "line_items.id": item },
                { "$set": { "line_items.$.review_request_sent": false } },
                callback
              );
            },
            callback
          );
        },
        function(err) {
          if (err) throw err;
          // done
        }
      );
    }
  );

.aggregate()结果不仅与文档匹配,而且从不存在该字段的数组中过滤出内容,以便仅返回该特定子文档的"id".

Where the .aggregate() result not only matches the documents, but filters out content from the array where the field was not present, so as to just return the "id" of that particular sub-document.

然后,循环的.update()语句匹配每个文档中找到的每个数组元素,并在匹配的位置添加缺少值的字段.

Then the looped .update() statements match each found array element in each document and adds the missing field with a value at the matched position.

这样,您将在以前缺少该文档的每个文档的所有子文档中都有该字段.

In that way you will have the field present in all sub-documents of every document where it was missing before.

如果您想做这样的事情,那么更改您的架构以确保该字段也总是存在也是明智的:

If you want to do such a thing, then it would also be wise to change your schema to make sure the field is always there as well:

{id: Number,
  line_items: [{ 
    id: String,
    quantity: Number,
    review_request_sent: { type: Boolean, default: false }
  }],
  total_price: String,
  name: String,
  order_number: Number
}

因此,下次您在代码中将新项目添加到数组时,如果未另外进行明确设置,则该元素将一直存在且具有其默认值.这样做,以及在您一直想要的其他字段(例如"id")上设置required,可能是一个好主意.

So the next time you add new items to the array in your code the element will always exist with it's default value if not otherwise explicitly set. And it is probably a goood idea to do so, as well as setting required on other fields you always want, such as "id".

这篇关于检查数组的子文档中是否存在该字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆