将插入对象合并到MongoDB文档中

时间:2017-03-25 10:33:08

标签: mongodb mongodb-query

假设我有以下文档。

[
  {
    "username": "admin",
    "accessControl": [
      {
        "methods": ["GET", "PUT"],
        "items": ["A", "B"]
      }
      {
        "methods": ["GET", "PUT", "CREATE"],
        "items": ["C"]
      }
    ]
  }, {
    "username": "user_1",
    "accessControl": [
      {
        "methods": ["GET", "PUT"],
        "items": ["A"]
      }
    ]
  }, {
    "username": "user_2"
  }
]

我需要在文档中插入以下内容。

{
  "accessControl": [{
    "methods": ["GET", "PUT"],
    "items": ["B"]
  }]
}

根据当前结构,需要将插入的部分合并到docs中。因此,如果accessControl不存在,则需要使用插入的项创建;

如果存在accessControl数组且包含"methods": ["GET", "PUT"]的对象,则需要将项"B"推入对象的"items"数组中。

如果存在accessControl数组,但不包含"methods": ["GET", "PUT"]的对象,则需要插入accessControl { "methods": ["GET", "PUT"], "items": ["B"] }

以后我可以拥有以下文档结构。

[
  {
    "username": "admin",
    "accessControl": [
      {
        "methods": ["GET", "PUT"],
        "items": ["A", "B"] //nothing inserted here since "B" is already present
      }, {
        "methods": ["GET", "PUT", "CREATE"],
        "items": ["C"]
      }
    ]
  }, {
    "username": "user_1",
    "accessControl": [
      {
        "methods": ["GET", "PUT"],
        "items": ["A", "B"] //item "B" has inserted here
      }
    ]
  }, {
    "username": "user_2",
    "accessControl": [
      {
        "methods": ["GET", "PUT"],
        "items": ["B"] // item "B" is inserted along with the whole "accessControl"
      }
    ]
  }
]

2 个答案:

答案 0 :(得分:1)

我没有看到如何在单个数据库查询中实现此目的。

我认为你需要先更新那些"方法"项目"匹配"。

let data = { "methods" : [ "GET", "PUT" ], "items" : [ "B" ] };

db.collection.updateMany(
    { "accessControl.methods": { "$all": [ "GET", "PUT" ] } }, 
    { "$addToSet": { 
        "accessControl.$.items": {"$each": data.items } 
    }}
)

然后更新"方法"的所有文件。字段不存在或与输入数据不匹配。

db.collection.updateMany(
    { "accessControl.methods": { 
        "$not": { "$all": [ "GET", "PUT" ] }
    }}, 
    { "$push": { "accessControl.items": data } }
);

答案 1 :(得分:1)

我建议您考虑更改数据库结构。如果accesscontrol数组每个项目有一个文档,并且该对象允许使用一组方法,则此类更新会更容易。

所以你的收藏会是这样的:

[
  {
    "username": "admin",
    "accessControl": [
      {
        "item" : "A",
        "methods": ["GET", "PUT"],
      },
      {
        "item" : "B",
        "methods": ["GET", "PUT"]
      },
      {
        "item": "C",
        "methods": ["GET", "PUT", "CREATE"],
      }
    ]
  },
  {
    "username": "user_1",
    "accessControl": [
      {
        "item": "A",
        "methods": ["GET", "PUT"]
      }
    ]
  },
  {
    "username": "user_2"
  }
]

您可以使用以下查询更新它:

db.collection.update(
  {"accessControl.item" : {$ne: "B"}},
  {$push: {"accessControl" : {"item" : "B"}}},
  {multi: true}
);

db.collection.update(
  {"accessControl.item" : "B"},
  {$addToSet: { "accessControl.$.methods" : {$each: ["GET", "PUT"]} } },
  {multi: true}
);

保留这样的数据:

[
  {
    "username" : "admin",
    "accessControl" : [ 
      {
        "item" : "A",
        "methods" : ["GET", "PUT"]
      }, 
      {
        "item" : "B",
        "methods" : ["GET", "PUT"]
      }, 
      {
        "item" : "C",
        "methods" : ["GET", "PUT", "CREATE"]
      }
    ]
  },
  {
    "username" : "user_1",
    "accessControl" : [ 
      {
        "item" : "A",
        "methods" : ["GET", "PUT"]
      }, 
      {
        "item" : "B",
        "methods" : ["GET", "PUT"]
      }
    ]
  },
  {
    "username" : "user_2",
    "accessControl" : [ 
      {
        "item" : "B",
        "methods" : ["GET", "PUT"]
      }
    ]
  }
]

注意:

  1. 查询实施由https://stackoverflow.com/a/31871281/174843提供。
  2. 遗憾的是,有两个单独的更新查询是必要的;能够将$addToSet operator用于单个查询会很好,但是文档说“你不能指定MongoDB只比较文档中的一部分字段来确定文档是否是现有数组元素的副本“因此它不适用于具有”B“的现有条目和没有的文档的两个文档。
  3. 重组将使其他查询更容易,例如查询用户在给定项目上允许的方法。