在Mongo中插入具有数组大小的字段

8

我在mongodb中有一些包含数组的文档。现在我需要一个字段,其中包含此数组中项目的数量。因此,我需要更新文档以添加此字段。 简单地说,我认为可以这样做:

db.myDocument.update({
     "itemsTotal": {
         $exists: false
     },
     "items": {
         $exists: true
     }
 }, {
     $set: {
         itemsTotal: {
             $size: "$items"
         }
     }
 }, {
 multi: true
 })

但是它以“不适合存储”完成。 此外,我尝试进行聚合,但它抛出异常:
"errmsg" : "exception: invalid operator '$size'",
"code" : 15999,
"ok" : 0

什么是最佳解决方案,以及我做错了什么?我正在考虑编写Java工具来计算总数并更新文档。

3个回答

3
你可以使用.aggregate()方法来$project你的文档并返回项目数组的$size。之后,您需要使用.forEach循环遍历聚合结果,并使用"Bulk"操作为您的文档$set itemTotal 字段以实现最大效率。
var bulkOp = db.myDocument.initializeUnorderedBulkOp(); 
var count = 0;

db.myDocument.aggregate([
    { "$match": { 
        "itemsTotal": { "$exists": false } ,
        "items": { "$exists": true }
    }}, 
    { "$project": { "itemsTotal": { "$size": "$items" } } }
]).forEach(function(doc) { 
        bulkOp.find({ "_id": doc._id }).updateOne({ 
            "$set": { "itemsTotal": doc.itemsTotal }
        });
        count++;
        if (count % 200 === 0) {
            // Execute per 200 operations and re-init
            bulkOp.execute();
            bulkOp = db.myDocument.initializeUnorderedBulkOp();
        }
})

// Clean up queues
if (count > 0) { 
    bulkOp.execute();
}

1
你可以初始化一个Bulk()操作构造器,按照以下方式在循环中更新文档:
var bulk = db.collection.initializeOrderedBulkOp(),   
    count = 0;

db.collection.find("itemsTotal": { "$exists": false },
     "items": {
         $exists: true
     }
).forEach(function(doc) { 
    var items_size = doc.items.length;
    bulk.find({ "_id": doc._id }).updateOne({ 
        "$set": { "itemsTotal": items_size }
    });
    count++;
    if (count % 100 == 0) {
        bulk.execute();
        bulk = db.collection.initializeUnorderedBulkOp();
    }
});

if (count % 100 != 0) { bulk.execute(); }

1

从MongoDB v3.4开始,这变得更加容易了,该版本引入了$addFields聚合管道操作符。我们还将使用$out运算符将聚合的结果输出到同一集合中(替换现有集合是原子性的)。

db.myDocuments.aggregate( [
  {
    $addFields: {
      itemsTotal: { $size: "$items" } ,
    },
  },
  {
    $out: "myDocuments"
  }
] )

警告:该解决方案要求所有文档都具有items字段。如果某些文档没有该字段,则aggregate将失败,显示

"$size的参数必须是数组,但类型为:missing"

您可能认为可以添加一个$match到聚合中,仅过滤包含items的文档,但这意味着所有不包含items的文档将不会被输出回myDocuments集合,因此您将永久失去这些文档。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接