【问题标题】:Adding sub documents to an array from within the same document从同一文档中将子文档添加到数组
【发布时间】:2016-08-16 17:08:54
【问题描述】:

我在同一个集合中有多个文档。这是前两个文件:

/* 1 */
{
    "_id" : ObjectId("57b21ba6770fbe3753ddfb6f"),
    "activeDateTime" : "11/5/2001",
    "enabled" : 0,
    "regionDescRefId" : ObjectId("5591bdbc807504cd138c9f38"),
    "patientType" : [ 
        ObjectId("5500744ee4b09a58a08b72b5")
    ],
    "allergenWells" : [ 
        {
            "allergenRefId" : 9,
            "column" : 1,
            "row" : 1
        }
    ]
}

/* 2 */
{
    "_id" : ObjectId("57b21ba6770fbe3753ddfb70"),
    "activeDateTime" : "11/5/2001",
    "enabled" : 0,
    "regionDescRefId" : ObjectId("5591bdbc807504cd138c9f38"),
    "patientType" : [ 
        ObjectId("5500744ee4b09a58a08b72b5")
    ],
    "allergenWells" : [ 
        {
            "allergenRefId" : 11,
            "column" : 2,
            "row" : 1
        }
    ]
}

我正在尝试从文档 #2 中获取 allergenWells 数组和字段值,并将它们放入文档 #1,使其看起来像这样:

/* 1 */
    {
        "_id" : ObjectId("57b21ba6770fbe3753ddfb6f"),
        "activeDateTime" : "11/5/2001",
        "enabled" : 0,
        "regionDescRefId" : ObjectId("5591bdbc807504cd138c9f38"),
        "patientType" : [ 
            ObjectId("5500744ee4b09a58a08b72b5")
        ],
        "allergenWells" : [ 
            {
                "allergenRefId" : 9,
                "column" : 1,
                "row" : 1
            },
            {
                "allergenRefId" : 11,
                "column" : 2,
                "row" : 1
            }
        ]
    }

因此,allergenWells 数组最终会增长。有任何想法吗?我是 MongoDB 的新手,因此非常感谢任何可以提供的帮助!

【问题讨论】:

  • 文档 #2 会发生什么?你想在这个操作之后更新集合还是只需要返回一个包含上述结果的文档?
  • document #2 将消失,任何其他添加的文档(document #3、document #4 等)也会消失。因此,我想要在同一个集合中添加多个文档将 allergenWells 字段和值添加到文档 #1 的 allergenWells 数组中。我也在使用 v2.6
  • 我下面的回答解决了你的问题吗?

标签: mongodb


【解决方案1】:

有几种方法可以解决这个问题。第一个是通过聚合框架方式。这是当您想要聚合文档而不是更新集合的结果时。

在这种情况下,您需要运行包含 $unwind 管道的聚合操作,以展平 allergenWells 数组,以便稍后使用 $group 进行聚合强>管道。这允许您按不同的键对文档进行分组,并使用 $addToSet 运算符创建一个合并数组。

考虑以下示例:

db.collection.aggregate([
    { "$unwind": "$allergenWells" },
    {
        "$group": {
            "_id": {
                "activeDateTime": "$activeDateTime",
                "enabled": "$enabled",
                "regionDescRefId": "$regionDescRefId",
                "patientType": "$patientType"
            },
            "id": { "$min": "$_id" },
            "allergenWells": { "$addToSet": "$allergenWells" }
        }
    },
    {
        "$project": {
            "_id": "$id",
            "activeDateTime": "$_id.activeDateTime",
            "enabled": "$_id.enabled",
            "regionDescRefId": "$_id.regionDescRefId",
            "patientType": "$_id.patientType",
            "allergenWells": 1
        }
    }
])

样本输出

/* 1 */
{
    "_id" : ObjectId("57b21ba6770fbe3753ddfb6f"),
    "allergenWells" : [ 
        {
            "allergenRefId" : 11,
            "column" : 2,
            "row" : 1
        }, 
        {
            "allergenRefId" : 9,
            "column" : 1,
            "row" : 1
        }
    ],
    "activeDateTime" : "11/5/2001",
    "enabled" : 0,
    "regionDescRefId" : ObjectId("5591bdbc807504cd138c9f38"),
    "patientType" : [ 
        ObjectId("5500744ee4b09a58a08b72b5")
    ]
}

但是,上述方法存在一些限制,尤其是当您计划让 allergenWells 数组增长,最终导致文档大小超过 16MB 或使用过多的系统内存时。 在客户端而不是数据库服务器中进行数组的内存合并可能更具可扩展性。


当您想要通过合并两个文档并删除另一个来更新集合时,另一种方法是理想的。这不能以原子方式完成,因为您需要遍历上述结果, 首先查询文档,找出您想要 $set 的内容,然后使用聚合中的值作为匹配过滤器更新文档,以确保您不会在两者之间获得并发更新并删除带有删除命令的其他文档。

下面的例子展示了这个概念:

db.collection.aggregate([
    { "$unwind": "$allergenWells" },
    {
        "$group": {
            "_id": {
                "activeDateTime": "$activeDateTime",
                "enabled": "$enabled",
                "regionDescRefId": "$regionDescRefId",
                "patientType": "$patientType"
            },
            "id": { "$min": "$_id" },
            "allergenWells": { "$addToSet": "$allergenWells" },
            "duplicates": { "$addToSet": "$_id" }
        }
    },
    {
        "$project": {
            "_id": "$id",
            "allergenWells": 1,
            "dupes": { "$setDifference": ["$duplicates", ["$id"]] }
        }
    }
]).forEach(function(doc){
    db.collection.update(
        { "_id": doc._id },
        { "$set": { "allergenWells": doc.allergenWells } }
    ); // update allergenWells array
    db.collection.remove({ "_id": { "$in": doc.dupes } }) // delete other docs
})

【讨论】:

  • 嘿,chridam。感谢您的答复。第二种方法是我一直在寻找的。我需要解决问题的“推动”就足够了。你太棒了!
  • @SamTheMan 不用担心,很高兴为您提供帮助
【解决方案2】:

可以使用$push的mongodb

在你的情况下,它看起来像这样。

db.collection.update({
  patientType: <mypatientId>
}, {
  $push: {
    allergenWells: {
      $each: {
        "allergenRefId" : 11,
        "column" : 2,
        "row" : 1
      }
    }
  }
});

【讨论】:

    猜你喜欢
    • 2014-07-29
    • 1970-01-01
    • 2012-09-28
    • 2012-04-12
    • 1970-01-01
    • 1970-01-01
    • 2021-06-17
    • 2015-12-21
    • 1970-01-01
    相关资源
    最近更新 更多