更新mongo 3.5嵌套数组中的值

时间:2020-02-12 06:01:40

标签: arrays mongodb mongodb-query aggregate mongotemplate



我想进行一次upsert调用来更新以及将数据插入到mongo db的嵌套数组中。

这是我的mongo文件。

  {
    "_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
                }
            ]
        }
    ]
}

这是我的要求,

  1. 让我说我有一个ID,即 575 (_id)
  2. 然后我将拥有嵌套的数组ID,即 fxLO68XyMR (spyneSharePhotoList._id)
  3. 然后,我将使用嵌套的电子邮件ID作为ID,即 chittaranjan@eventila.com (spyneSharePhotoList.spyneShareUsers._id)和 selectedByClient (布尔值)

现在我要检查的是此ID(spyneSharePhotoList.spyneShareUsers._id)是否已存在于所需位置中,我要根据其更新布尔值,即 selectedByClient (是/否)电子邮件ID。

如果数组中没有id,它将创建一个新条目。为

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

spyneShareUsers 列表中。

请帮助我完成此任务。谢谢

1 个答案:

答案 0 :(得分:0)

这可能不是最聪明的解决方案,但它应该可以工作:

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);
})

我没有检查MongoDB 3.5中是否所有操作符都可用

我的目标是处理聚合管道中的所有内容,最后只运行一个replaceOne()

这是另一种基于$map运算符的解决方案:

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);
})

您还可以通过两次更新获得相同的结果:

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 }] }
)