在没有localField

时间:2018-11-09 08:56:17

标签: mongodb aggregation

我使用MongoDB存储由A腿和B腿组成的呼叫详细记录。

它们之间的关系如下:

  • 所有记录(A和B腿)都在同一cdr集合中
  • A腿的字段leg_type等于a,B腿的字段当然是b
  • B腿有一个字段a_leg,以指示它们属于哪个A腿。

此刻,我们检索所需的A形腿,然后遍历它们,对于每个A形腿,我们都检索相关的B形腿(可以是多个),因此全部在客户端。

我想知道是否可以在一个查询中做到这一点,显然您可以使用$lookup (aggregation)。但是,在这种情况下,似乎需要在A形腿上引用一个字段,该字段将是B形腿的数组。
但是我没有那个领域,在我花不必要的时间来建立这样一个领域之前,我想知道我是否可以做不同的事情。

为完整起见,这是我们现在检索CDR的方式:

    a_legs = mongo_db['cdr'] \
        .find({'group_id': group.id, 'leg_type': 'a'}) \
        .sort('times.created', pymongo.DESCENDING) \
        .limit(50)

    for cdr in a_legs:
        # Find B-legs
        cdr['b_legs'] = mongo_db['cdr'] \
            .find({'a_leg': cdr['call_id'], 'leg_type': 'b'}) \
            .sort('times.created', pymongo.ASCENDING)

因此,最重要的问题是:我们可以在对MongoDB的单个查询中完成上述操作吗?

我试图这样做:

db.cdr.aggregate([{
    $lookup: {
        from: "cdr",
        localField: "call_id",
        foreignField: "a_leg",
        as: "b_legs"
    }
}])

但是它没有显示结果。

1 个答案:

答案 0 :(得分:0)

我在Studio3T的帮助下找到了答案,它帮助我逐步构建了查询。这就是我最终得到的:

mongo_db['cdr'].aggregate(
    [
        { 
            "$match" : {
                "group_id" : 585, 
                "leg_type" : "a"
            }
        }, 
        { 
            "$lookup" : {
                "from" : "cdr", 
                "let" : {
                    "call_id" : "$call_id"
                }, 
                "pipeline" : [
                    {
                        "$match" : {
                            "$expr" : {
                                "$and" : [
                                    {
                                        "$eq" : [
                                            "$leg_type", 
                                            "b"
                                        ]
                                    }, 
                                    {
                                        "$eq" : [
                                            "$a_leg", 
                                            "$$call_id"
                                        ]
                                    }
                                ]
                            }
                        }
                    }, 
                    {
                        "$project" : {
                            "_id" : False, 
                            "raw" : False, 
                            "leg_type" : False
                        }
                    }, 
                    {
                        "$sort" : {
                            "times.created" : 1
                        }
                    }
                ], 
                "as" : "b_legs"
            }
        }, 
        { 
            "$project" : {
                "_id" : False, 
                "raw" : False, 
                "leg_type" : False
            }
        }
    ], 
    { 
        "allowDiskUse" : False
    }
);

我需要将$ lookup与pipeline一起使用。我还必须在call_id上创建课程索引,以使其快速运行。