MongoDB создает массив массивов в $ group $ push вместо плоского массива - PullRequest
2 голосов
/ 04 июня 2019

Я пытаюсь сгруппировать набор документов после операции $ unwind. Мои документы выглядят так:

{ 
    "_id" : ObjectId("5cdb5b5acadf5100019da2f4"), 
    "allowedLocations" : [
        {
            "type" : "country", 
            "value" : "world", 
            "label" : "World"
        }
    ], 
    "disallowedLocations" : [
        {
            "type" : "country", 
            "value" : "CF", 
            "label" : "Central African Republic"
        }, 
        {
            "type" : "country", 
            "value" : "CN", 
            "label" : "China"
        }
    ], 
}

{ 
    "_id" : ObjectId("5cdb5b5acadf5100019da2f4"), 
    "allowedLocations" : [
        {
            "type" : "country", 
            "value" : "US", 
            "label" : "United States of America"
        }
    ], 
    "disallowedLocations" : [
        {
            "type" : "country", 
            "value" : "CA", 
            "label" : "Canada"
        }, 
        {
            "type" : "country", 
            "value" : "MX", 
            "label" : "Mexico"
        }
    ], 
}

Я хочу сгруппировать их по _id, а затем объединить массивы allowLocations и disallowedLocations в один. Групповой этап в моем конвейере выглядит так:

{ 
    "$group" : {
        "_id" : "$_id", 
        "allowedLocations" : {
            "$push" : "$allowedLocations"
        }, 
        "disallowedLocations" : {
            "$push" : "disallowedLocations"
        }
    }
}

Проблема в том, что в результате я получаю не документ с объединенными обоими массивами, а массив массивов, каждый элемент которого является массивом каждого документа:

{ 
    "_id" : ObjectId("5cdb5b5acadf5100019da2f4"), 
    "allowedLocations" : [
        [
            {
                "type" : "country", 
                "value" : "US", 
                "label" : "United States of America"
            }
        ],
        [
            {
                "type" : "country", 
                "value" : "world", 
                "label" : "World"
            }
        ],
    ], 
    "disallowedLocations" : [
        [
            {
                "type" : "country", 
                "value" : "CF", 
                "label" : "Central African Republic"
            }, 
            {
                "type" : "country", 
                "value" : "CN", 
                "label" : "China"
            }
        ],
        [
            {
                "type" : "country", 
                "value" : "CA", 
                "label" : "Canada"
            }, 
            {
                "type" : "country", 
                "value" : "MX", 
                "label" : "Mexico"
            }
        ]
    } 
}

Есть ли способ создать плоский массив только с объектами в качестве элементов? Я также пытался использовать $ concatArrays перед отправкой, но это создает больше массивов внутри массивов.

1 Ответ

2 голосов
/ 04 июня 2019

Два решения здесь. Вы можете запустить $ unwind в обоих массивах, чтобы получить по одному allowed и disallowed location на документ, а затем запустить этап $ group :

db.col.aggregate([
    {
        $unwind: "$allowedLocations"
    },
    {
        $unwind: "$disallowedLocations"
    },
    { 
        "$group" : {
            "_id" : "$_id", 
            "allowedLocations" : {
                "$addToSet" : "$allowedLocations"
            }, 
            "disallowedLocations" : {
                "$addToSet" : "$disallowedLocations"
            }
        }
    }
])

или вы можете сначала запустить свою $ группу , а затем использовать $ уменьшение , чтобы сгладить allowedLocations и disallowedLocations:

db.col.aggregate([
    { 
        "$group" : {
            "_id" : "$_id", 
            "allowedLocations" : {
                "$push" : "$allowedLocations"
            }, 
            "disallowedLocations" : {
                "$push" : "$disallowedLocations"
            }
        }
    },
    {
        $project: {
            _id: 1,
            allowedLocations: {
                $reduce: {
                    input: "$allowedLocations",
                    initialValue: [],
                    in: { $concatArrays: [ "$$value", "$$this" ] }
                }
            },
            disallowedLocations: {
                $reduce: {
                    input: "$disallowedLocations",
                    initialValue: [],
                    in: { $concatArrays: [ "$$value", "$$this" ] }
                }
            }
        }
    }
])
...