Insert field with array size in mongo

后端 未结 3 643
遇见更好的自我
遇见更好的自我 2021-01-12 21:20

I have a documents in mongodb, containing some array. Now I need to have a field containing a quantity of items of this array. So I need to update documents adding this fiel

相关标签:
3条回答
  • 2021-01-12 21:29

    This is much easier starting with MongoDB v3.4, which introduced the $addFields aggregation pipeline operator. We'll also use the $out operator to output the result of the aggregation to the same collection (replacing the existing collection is atomic).

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

    WARNING: this solution requires that all documents to have the items field. If some documents don't have it, aggregate will fail with

    "The argument to $size must be an array, but was of type: missing"

    You might think you could add a $match to the aggregation to filter only documents containing items, but that means all documents not containing items will not be output back to the myDocuments collection, so you'll lose those permanently.

    0 讨论(0)
  • 2021-01-12 21:33

    You can use the .aggregate() method to $project your documents and return the $size of the items array. After that you will need to loop through your aggregation result using the .forEach loop and $set the itemTotal field for your document using "Bulk" operation for maximum efficiency.

    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();
    }
    
    0 讨论(0)
  • 2021-01-12 21:39

    You could initialise a Bulk() operations builder to update the document in a loop as follows:

    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(); }
    
    0 讨论(0)
提交回复
热议问题