【问题标题】:Merge data from two collections合并来自两个集合的数据
【发布时间】:2018-09-07 16:02:55
【问题描述】:

如果我有一些数据存储在 MongoDB 的两个集合中,如下所示:

集合 1:

opened = [{id: 1, value: 1123}, {id: 2, value: 4231}, {id: 2, value: 3322}...]

集合 2:

synched = [{id: 1, value: 12343}, {id: 2, value: 12322}, {id: 1, value: 12322}...]

现在我知道我可以对数据库进行两次调用并从两者中获取数据,但我有兴趣潜在地聚合调用并加入来自两个集合的数据,以便最终得到以下结果:

result = {synched: [{id: 1, value: 12343},{id: 1, value: 12322}], opened: [{id: 1, value: 1123}]}

所以就我而言,目前我只执行了两次标准查询:

db.opened.find({id: 1}, function(err, res){})
db.synched.find({id: 1}, function(err, res){})

有没有办法将它们结合起来?

编辑:

我发布的原始问题发生了一些变化。这是我需要处理的一个细微变化,以下答案不支持。

如果我有一个匹配的 id 数组怎么办:

{ $match: { 'id': {$in: [1,2]} }}

所以现在,limit 电话真的把这搞砸了。我需要的是来自synched 的所有文档和来自opened 的所有文档,它们与数组中的任何id 匹配,但只返回第一次遇到的限制。情况并非总是如此。可能有多个文档具有相同的 id 属性。该属性不是唯一的_id。

任何帮助将不胜感激。

【问题讨论】:

  • 你能分享你的mongodb版本吗?
  • 3.4.7 是我正在运行的 MongoDB

标签: mongodb mongoose aggregation-framework


【解决方案1】:

您可以在 mongodb 3.4 及更高版本中尝试以下聚合

db.synched.aggregate([
  { "$limit": 1 },
  { "$facet": { 
    "synched": [
      { "$match": { "id": 1  }}
    ],
    "opened": [
      { "$match": { "id": 1  }},
      { "$limit": 1 },
      { "$lookup": {
        "from": "opened",
        "localField": "id",
        "foreignField": "id",
        "as": "opened"
      }},
      { "$unwind": "$opened" },
      { "$replaceRoot": { "newRoot": "$opened" }}
    ]
  }},
  { "$project": { "opened": 1, "synched": 1 }}
])

并使用新的$lookup 语法

db.synched.aggregate([
  { "$facet": { 
    "synched": [
      { "$match": { "id"': { "$in": [1,2] }}}
    ],
    "opened": [
      { "$limit": 1 },
      { "$lookup": {
        "from": "opened",
        "pipeline": [
          { "$match": { "id"': { "$in": [1,2] }}}
        ],
        "as": "opened"
      }},
      { "$unwind": "$opened" },
      { "$replaceRoot": { "newRoot": "$opened" }}
    ]
  }},
  { "$project": { "opened": 1, "synched": 1 }}
])

【讨论】:

  • 谢谢!现在,只是关于潜在数据库设计决策的一般性问题。将这两个数据集组合成一个带有附加字段 type: synched 或 type:opened 的集合会更好,我可以在其中进行非聚合调用以查询两种文档类型,或者聚合和两个集合在这里是一个不错的选择?什么更有效?
  • 聚合总是一个更好的选择。好吧,这取决于您的项目要求,对此我无话可说。但是对于 mongodb,拆分文档总是一件好事(就像 sql 和它的 join 一样),之后我们可以使用 $lookup 和其他聚合技巧轻松合并为一个文档。
  • 抱歉,但当我意识到我想一次匹配多个 Id 时,我稍微修改了这个问题。你能再看看吗?
  • 好的,您能否将您的 mongodb 版本更新到 3.6 或更高版本,因为使用上述 $lookup 语法,您尝试做的事情非常昂贵,如果您可以将其更新到 3.6 或更高版本,那将是很多操作更简单、更省时。
  • 这很好用,我确实需要做一点小改动。我不得不删除同步管道上的第一个 limit 调用。发生的事情是我没有在同步数组中获得任何数据,以及与打开的数组匹配的所有数据。删除限制调用,导致所有匹配的文档从同步和所有匹配的文档从打开的集合被返回。这很不错。感谢您的帮助。
【解决方案2】:

这里我有两个集合Users和User Profile,

下面的方法将匹配请求的字段,同时结合两个集合并抛出所需的输出:

const getUserData = async (userId) => {
        const getUserDataByUserId = await userDataModel.aggregate([
            {
                $match: {
                    userId: userId
                }
            }, {
                $lookup: {
                    from: 'user_profiles',
                    localField: 'userId',
                    foreignField: 'userId',
                    as: 'users'
                }
            }, {
                $replaceRoot: {
                    newRoot: {
                        $mergeObjects: [{
                            $arrayElemAt: ["$users", 0]
                        }, "$$ROOT"]
                    }
                }
            }, {
                $project: {
                    fromItems: 0
                }
            }
        ]);

        return getUserDataByUserId;
    }

【讨论】:

    猜你喜欢
    • 2013-04-26
    • 2021-11-04
    • 1970-01-01
    • 2016-09-27
    • 1970-01-01
    • 2014-02-06
    • 1970-01-01
    • 2022-11-23
    • 1970-01-01
    相关资源
    最近更新 更多