我有一个类似的模式.

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

我想找到的是所有没有为数组中的所有项目设置field review_request_sent的文档.

实例

{ 
  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字段.

推荐答案

您基本上需要$elemMatch$exists运算符,因为这将判断每个元素,以查看条件"field not exists"(字段不存在)是否适用于任何元素:

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

});

仅当字段不在其中一个数组子文档中时才返回第二个文档:

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

请注意,此"不同"于此表格:

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

})

这是在问"所有"数组元素是否不包含此字段,如果文档中至少有一个元素存在此字段,则不是这样.因此,$eleMatch使条件针对"每个"数组元素进行测试,从而得到正确的响应.


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

    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".

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

这样一来,该字段将出现在以前丢失的每个文档的所有子文档中.

如果您想做这样的事情,那么更改模式以确保字段也始终存在也是明智的:

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

因此,下次在代码中向数组添加新项时,如果没有显式设置,元素将始终以其默认值存在.这样做可能是个好主意,同时在你一直想要的其他字段上设置required,比如"id".

Mongodb相关问答推荐

Mongo Aggregate管道-另一个集合中的多个查找

MongoDB:如何从数组中的所有对象中删除属性?

通过insertId MongoDB获取文档

mongo:在 mongodb 6.0 docker 容器上找不到命令

Mongodb聚合查找连接两个对象字段的集合数组匹配对象索引字段的总和

如何替换mongodb中的动态键?

mongodb - 查找包含至少 3 个填充数组的记录

MongoID find 或 find_by

根据 Month 删除 mongodb 中的旧记录

无法连接到mongolab主机

Mongo 可尾游标与 Redis 发布/订阅

将 MongoDB 数据库复制到本地计算机

有没有办法自动更新 MongoDB 中的两个集合?

Spring Data MongoDB 中的独特之处

MongoDB:如何在 100 个集合中找到 10 个随机文档?

Mongo Schema-less集合和 C#

mongoose 使用 $cond 中的 $exists 聚合

mongo中的稀疏索引和空值

缩短 MongoDB 属性名称值得吗?

mongoose中的 Date.now() 和 Date.now 有什么区别?