Update value in nested array of mongo 3.5

前提是你 提交于 2020-02-25 06:04:12

问题




I want to make an upsert call to update as well as insert my data in nested array of mongo db.

This is my mongo document.

  {
    "_id" : "575",
    "_class" : "com.spyne.sharing.SpyneShareUserProject",
    "spyneSharePhotoList" : [ 
        {
            "_id" : "fxLO68XyMR",
            "spyneShareUsers" : [ 
                {
                    "_id" : "chittaranjan@eventila.com",
                    "selectedByClient" : false
                }, 
                {
                    "_id" : "chittaranjan@gmail.com",
                    "selectedByClient" : false
                }
            ]
        }, 
        {
            "_id" : "nVpD0KoQAI",
            "spyneShareUsers" : [ 
                {
                    "_id" : "chittaranjan@eventila.com",
                    "selectedByClient" : true
                }
            ]
        }, 
        {
            "_id" : "Pm0B3Q9Igv",
            "spyneShareUsers" : [ 
                {
                    "_id" : "chittaranjan@gmail.com",
                    "selectedByClient" : true
                }
            ]
        }
    ]
}

Here my requirement is,

  1. lets say i have an ID i.e. 575 (_id)
  2. Then i will have the nested array ID i.e. fxLO68XyMR (spyneSharePhotoList._id)
  3. Then i will have nested email id as ID i.e. chittaranjan@eventila.com (spyneSharePhotoList.spyneShareUsers._id) and selectedByClient (boolean)

Now i want is to check if this ID (spyneSharePhotoList.spyneShareUsers._id) is already present in the desired location i want to update the boolean value i.e. selectedByClient (true / false) according to that email id.

If the id is not present in the array, the it will make a new entry. as

{
 "_id" : "chittaranjan@gmail.com",
 "selectedByClient" : false
}

in spyneShareUsers list.

Please help me to do this task. Thank you


回答1:


Most likely this is not the smartest solution, but it should work:

shareUserProject = {
   id: "575",
   PhotoListId: "fxLO68XyMR",
   ShareUserId: "chittaranjan_new@eventila.com"
}

db.collection.aggregate([
   { $match: { _id: shareUserProject.id } },
   {
      $facet: {
         root: [{ $match: {} }],
         update: [
            { $unwind: "$spyneSharePhotoList" },
            { $match: { "spyneSharePhotoList._id": shareUserProject.PhotoListId } },
            {
               $set: {
                  "spyneSharePhotoList.spyneShareUsers": {
                     $concatArrays: [
                        {
                           $filter: {
                              input: "$spyneSharePhotoList.spyneShareUsers",
                              cond: { $ne: ["$$this._id", shareUserProject.ShareUserId] }
                           }
                        },
                        [{
                           _id: shareUserProject.ShareUserId,
                           selectedByClient: { $in: [shareUserProject.ShareUserId, "$spyneSharePhotoList.spyneShareUsers._id"] }
                        }]
                     ]
                  }
               }
            }
         ]
      }
   },
   { $unwind: "$root" },
   { $unwind: "$update" },
   {
      $set: {
         "root.spyneSharePhotoList": {
            $concatArrays: [
               ["$update.spyneSharePhotoList"],
               {
                  $filter: {
                     input: "$root.spyneSharePhotoList",
                     cond: { $ne: ["$$this._id", shareUserProject.PhotoListId] }
                  }
               }
            ]
         }
      }
   },
   { $replaceRoot: { newRoot: "$root" } }
]).forEach(function (doc) {
   db.collection.replaceOne({ _id: doc._id }, doc);
})

I did not check whether all operators are available in MongoDB 3.5

My goal was to process everything in aggregation pipeline and run just a single replaceOne() at the end.

Here another solution based on $map operator:

db.collection.aggregate([
  { $match: { _id: shareUserProject.id } },
  {
    $set: {
      spyneSharePhotoList: {
        $map: {
          input: "$spyneSharePhotoList",
          as: "photoList",
          in: {
            $cond: {
              if: { $eq: [ "$$photoList._id", shareUserProject.PhotoListId ] },
              then: {
                "_id": "$$photoList._id",
                spyneShareUsers: {
                  $cond: {
                    if: { $in: [ shareUserProject.ShareUserId, "$$photoList.spyneShareUsers._id" ] },
                    then: {
                      $map: {
                        input: "$$photoList.spyneShareUsers",
                        as: "shareUsers",
                        in: {
                          $cond: {
                            if: { $eq: [ "$$shareUsers._id", shareUserProject.ShareUserId ] },
                            then: { _id: shareUserProject.ShareUserId, selectedByClient: true },
                            else: "$$shareUsers"
                          }
                        }
                      }
                    },
                    else: {
                      $concatArrays: [
                        "$$photoList.spyneShareUsers",
                        [ { _id: shareUserProject.ShareUserId, selectedByClient: false } ]
                      ]
                    }
                  }
                }
              },
              else: "$$photoList"
            }
          }
        }
      }
    }
  }
]).forEach(function (doc) {
   db.collection.replaceOne({ _id: doc._id }, doc);
})

You can achieve the same result also with two updates:

shareUserProject = {
   id: "575",
   PhotoListId: "fxLO68XyMR_x",
   ShareUserId: "chittaranjan_new@gmail.com"
}

ret = db.collection.updateOne(
   { _id: shareUserProject.id },
   { $pull: { "spyneSharePhotoList.$[photoList].spyneShareUsers":  { _id: shareUserProject.ShareUserId } } },
   { arrayFilters: [{ "photoList._id": shareUserProject.PhotoListId }] }
)


db.collection.updateOne(
   { _id: shareUserProject.id },
   { $push: { "spyneSharePhotoList.$[photoList].spyneShareUsers":  { _id: shareUserProject.ShareUserId, selectedByClient: ret.modifiedCount == 1 } } },
   { arrayFilters: [{ "photoList._id": shareUserProject.PhotoListId }] }
)


来源:https://stackoverflow.com/questions/60182047/update-value-in-nested-array-of-mongo-3-5

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!