【问题标题】:Merge insert objects into MongoDB documents将插入对象合并到 MongoDB 文档中
【发布时间】:2017-03-27 18:57:47
【问题描述】:

假设我有以下文档。

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

插入的部分需要按照当前结构合并到文档中。因此如果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"
      }
    ]
  }
]

【问题讨论】:

  • 是否可以选择更改数据库结构?如果 accesscontrol 数组的每个 item 有一个文档,并且该对象上允许使用一组方法,则这种更新可能会更容易。
  • 我想我会走那条路。改变结构看起来很有帮助

标签: mongodb mongodb-query


【解决方案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”现有条目的文档和没有“B”条目的文档。
  3. 重组还将使其他查询变得更容易,例如查询用户在给定项目上允许的方法。

【讨论】:

    【解决方案2】:

    我看不到如何在单个数据库查询中实现这一目标。

    我认为您需要首先更新“方法”项“匹配”的那些文档。

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

    然后更新所有“methods”字段不存在或与输入数据不匹配的文档。

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

    【讨论】:

    • 感谢您的洞察力。看起来单个数据库查询是不可能的。我会在结构上多做一些工作,让一些更友好的东西。
    猜你喜欢
    • 2020-11-08
    • 1970-01-01
    • 1970-01-01
    • 2016-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-17
    相关资源
    最近更新 更多