【问题标题】:MongoDB: efficient way to join collections inside a facetMongoDB:在构面内加入集合的有效方法
【发布时间】:2020-01-16 21:48:38
【问题描述】:

我有一个聚合可以概括为:

db.getCollection('originalCollection').aggregate([
    $match: { //some filters }
    $project: { //some transformations}
    $facet: {
        "collectionA": [ //some transformation steps ],
        "collectionB": [ //some other transformation steps ]
    }
...

现在我想使用id 字段与集合AB 进行类似SQL 的连接。例如,如果我在集合 A 中有此文档:

{
    id: "A"
    property1: "a value"
}

这个文档在集合B:

{
    id: "A"
    property2: "other value"
}

生成的集合必须包含:

{
   id: "A",
   property1: "a value",
   property2: "other value"
}

我尝试作为下一个聚合步骤在集合 A 上使用 $map,它使用 $filter 来匹配集合 B 中具有相同 ID 的文档,但速度非常慢:

{
    "$project": {
        "tmpResult": {
            "$map": {
                "input": "$collectionA",
                "as": "collectionADocument",
                "in": {
                    "property1": "$$collectionADocument.property1",
                    "property2": {
                        "$arrayElemAt": [
                            {
                                "$filter": {
                                    "input": "$collectionB",
                                    "cond": {
                                        "$eq": [
                                            "$$collectionADocument.id",
                                            "$$this.id"
                                        ]
                                    }
                                }
                            },
                            0
                        ]
                    }
                }
            }
        }
    }
}

在构面中实现两个集合连接的最快方法是什么?提前致谢!

【问题讨论】:

  • $filters 非常快,分享一下collectionAcollectionB 数组有多少项。其他解决方案可能是$concatArrays [collectionA, collectionB] + $unwind + $group + $mergeObjects。您可以进行基准测试以选择最佳方式...

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

为什么不使用 $lookup,添加到聚合管道的 $lookup 运算符本质上与左外连接相同:

https://docs.mongodb.org/master/reference/operator/aggregation/lookup/#pipe._S_lookup

来自文档,

{
   $lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }
}

对于您的示例,可能如下所示,


db.B.aggregate({
   $lookup:
     {
       from: "A",
       localField: "id",
       foreignField: "id",
       as: "AB"
     }
})

【讨论】:

  • 问题是我不能在单个聚合中拥有。然后我必须删除集合 A、B 等。
  • 那么,您想要一个具有多个聚合管道的解决方案..?为什么你必须删除集合A,B..?我不明白你的顾虑。
  • 为了简单起见,我想要一个聚合。如果有多个聚合,那么我必须删除像 A 和 B 这样的中间集合,因为它们没有用。
猜你喜欢
  • 2016-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-22
  • 2015-04-08
  • 1970-01-01
  • 2019-07-28
  • 2012-09-15
相关资源
最近更新 更多