Получить связанные объекты в MongoDB без localField - PullRequest
0 голосов
/ 09 ноября 2018

Я использую MongoDB для хранения записей сведений о вызовах, которые состоят из А-ножек и В-ножек.

Они связаны следующим образом:

  • Все записи (A & B-ноги) находятся в одной cdr коллекции
  • А-ноги имеют поле leg_type, равное a, B-ноги имеют b, конечно
  • B-ноги имеют поле a_leg, чтобы указать, к какой A-ноге они принадлежат.

В данный момент мы получаем нужные нам A-ветви, затем перебираем их, и для каждой A-ветви мы получаем соответствующие B-ветви (может быть несколько), поэтому все на стороне клиента.

Мне было интересно, смогу ли я сделать это в одном запросе, и, очевидно, вы можете это сделать с помощью $ lookup (aggregation) . Однако в данном случае, по-видимому, необходимо указывать поле на А-ветви, которое будет представлять собой массив В-ветвей.
Но у меня нет этого поля, и прежде чем я потратил ненужное время, чтобы получить такое поле, мне было интересно, могу ли я сделать это по-другому.

Для полноты, вот как мы сейчас получаем 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 голосов
/ 09 ноября 2018

Я понял это с помощью 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, чтобы он работал быстро.

...