MongoDB проекция на конкретные вложенные свойства - PullRequest
0 голосов
/ 26 сентября 2018
"data" : {
    "visits" : {
        "daily" : {
            "2018-09-05" : 3586,
            "2018-09-06" : 2969,
            "2018-09-07" : 2624,
            "2018-09-08" : 2803,
            "2018-09-09" : 3439,
            "2018-09-10" : 3655
        }
    }
},

У меня есть структура свойств в MongoDB, как это, что я пытаюсь сделать, если у меня есть даты начала и окончания, например (2018-09-06 - 2018-09-07), я хочучтобы получить результат в этом формате

"data" : {
    "visits" : {
        "daily" : {
            "2018-09-06" : 2969,
            "2018-09-07" : 2624
        }
    }
},

Есть ли эффективный способ сделать это динамически?Я могу сделать это, вставив в прогнозы такие вещи, как {{data.visits.daily.2018-09-06 ": 1," data.visits.daily.2018-09-07 ": 1}, и это работает, но это немне не кажется хорошим решением.

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018

Использование MongoDB 3.4.4 и более новых версий:

db.collection.aggregate([
    { "$addFields": { 
        "data.visits.daily": {
            "$arrayToObject": {
                "$filter": {
                    "input": { "$objectToArray": "$data.visits.daily" },
                    "as": "el",
                    "cond": {
                        "$and": [
                            { "$gte": ["$$el.k", "2018-09-06"] },
                            { "$lte": ["$$el.k", "2018-09-07"] },
                        ]
                    }
                }
            }
        }
    } }
])

Приведенный выше конвейер выдаст окончательный результат

{
    "data" : {
        "visits" : {
            "daily" : {
                "2018-09-06" : 2969,
                "2018-09-07" : 2624
            }
        }
    }
}

Пояснения

Конвейер может быть разложен, чтобы показать результаты каждого отдельного оператора.

$objectToArray

$objectToArray позволяет преобразовывать документ с динамическимключи в массив, который содержит элемент для каждой пары поле / значение в исходном документе.Каждый элемент в массиве возврата является документом, который содержит два поля k и v.

Запуск конвейера только с оператором на $project этапе

db.collection.aggregate([
    { "$project": {
        "keys": { "$objectToArray": "$data.visits.daily" }
    } }
])

урожайность

{
    "_id" : ObjectId("5bab6d09b1951fef20a5dce4"),
    "keys" : [ 
        {
            "k" : "2018-09-05",
            "v" : 3586
        }, 
        {
            "k" : "2018-09-06",
            "v" : 2969
        }, 
        {
            "k" : "2018-09-07",
            "v" : 2624
        }, 
        {
            "k" : "2018-09-08",
            "v" : 2803
        }, 
        {
            "k" : "2018-09-09",
            "v" : 3439
        }, 
        {
            "k" : "2018-09-10",
            "v" : 3655
        }
    ]
}

$filter

$filter* 1049Оператор * действует как механизм фильтрации для массива, созданного оператором $objectToArray, работает путем выбора подмножества массива для возврата на основе указанного условия, которое становитсяВаш запрос.

Рассмотрим следующий конвейер, который возвращает массив пары ключ / значение, который соответствует условию "2018-09-06" <= key <= "2018-09-07"

db.collection.aggregate([
    { "$project": {
        "keys": { 
            "$filter": {
                "input": { "$objectToArray": "$data.visits.daily" },
                "as": "el",
                "cond": {
                    "$and": [
                        { "$gte": ["$$el.k", "2018-09-06"] },
                        { "$lte": ["$$el.k", "2018-09-07"] },
                    ]
                }
            }  
        }
    } }
])

, что дает

{
    "_id" : ObjectId("5bab6d09b1951fef20a5dce4"),
    "keys" : [ 
        {
            "k" : "2018-09-06",
            "v" : 2969
        }, 
        {
            "k" : "2018-09-07",
            "v" : 2624
        }
    ]
}

$arrayToObject

Преобразует отфильтрованный массив выше из

[ 
    {
        "k" : "2018-09-06",
        "v" : 2969
    }, 
    {
        "k" : "2018-09-07",
        "v" : 2624
    }
]

в исходный документ с динамическим ключом

{
    "2018-09-06" : 2969,
    "2018-09-07" : 2624
}

так что при запуске конвейера

db.collection.aggregate([
    { "$project": { 
        "keys": {
            "$arrayToObject": {
                "$filter": {
                    "input": { "$objectToArray": "$data.visits.daily" },
                    "as": "el",
                    "cond": {
                        "$and": [
                            { "$gte": ["$$el.k", "2018-09-06"] },
                            { "$lte": ["$$el.k", "2018-09-07"] },
                        ]
                    }
                }
            }
        }
    } }
])

будет получено

{
    "_id" : ObjectId("5bab6d09b1951fef20a5dce4"),
    "keys" : {
        "2018-09-06" : 2969,
        "2018-09-07" : 2624
    }
}

Но, конечно, вы захотите сохранить исходную схему, то есть текущие поля, поэтому вам нужно будет использовать $addFields вместо $project трубопровода, используемого для иллюстрации.

$addFields

Это эквивалентно этапу $project, который явно указывает все существующие поля во входных документах и ​​добавляет новые поля.Указание существующего имени поля в операции $addFields приводит к замене исходного поля, и вам нужно будет использовать точечную нотацию для обновления встроенного поля data.visits.daily с помощьюдинамические клавиши.

0 голосов
/ 26 сентября 2018

Этого можно добиться с помощью следующей агрегации:

var startdate = "2018-09-06";
var enddate = "2018-09-09";
db['01'].aggregate(
    [
        {
            $project: {
               daily:{$objectToArray:"$data.visits.daily"}
            }
        },
        {
            $unwind: {
                path : "$daily",

            }
        },
        {
            $addFields: {
                "date": {$dateFromString:{dateString:"$daily.k",format:"%Y-%m-%d"}}
            }
        },
        {
            $match: {
            $and:[{date:{$gte:new Date(startdate)}},{date:{$lte:new Date(enddate)}}]
            }
        },
        {
            $group: {
            _id:"_id",
            daily:{$push:"$daily"}
            }
        },
        {
            $project: {
                "data.visits.daily":{$arrayToObject:"$daily"}
            }
        },
    ]
);
...