MongoDb insert or add in embedded document

2019-06-10 08:16发布

问题:

This is my final document structure. I am on mongo 3.0.

   {
     _id: "1",
     stockA: [ { size: "S", qty: 25 }, { size: "M", qty: 50 } ],
     stockB: [ { size: "S", qty: 27 }, { size: "M", qty: 58 } ]
   }

I am randomly adding elements inside stockA or stockB collections. I would like come up with a query which would satisfy following rules:

  1. If item is not exist - create whole document and insert item in stock A or B collection.
  2. If item is exist but stock A or B collection is missing create stock collection and add element inside collection.
  3. if item is exist and stock collection is exist just append element inside collection.

Question: Is it possible to achieve all that in one query? My main requirement that current insert has to be extremely fast and scalable.

If yes, could you please help me to come up with required query.

If no, could you please guide me how do I achieve requirements in fastest and cleanest way.

Thanks for any help!

回答1:

The operator you are looking for is $addToSet or $push in combination with upsert:true.

Both operators can take multiple key/value pairs. It will then operate separately on each key. Both will create the array when it doesn't exist yet, and in either case will add the value.

The difference is that $addToSet will first check if an identical element already exists in the array. When performance is an issue, keep in mind that MongoDB must perform a linear search to do this. So for very large arrays, $addToSet can become quite slow.

The upsert:true option to the update function will result in the document being created when it isn't found.



回答2:

You can use the update method with the upsert option which will create a new document when no document matches the query criteria.

db.collection.update({ "_id": 1 },
    {
        "$push" : {
            "stockB" : {
                           "size" : "M",
                           "qty" : 51
            },
           "stockA" : {
                           "size" : "M",
                           "qty" : 21
            }
        }
    }, 
    { "upsert": true }
)