использование оператора $slice для получения последнего элемента массива в mongodb

Как получить последний элемент массива с условиями в MongoDB. Я не могу использовать ломтик. Вот мой код

{ "1" : { "relevancy" : [  "Y" ] }, "_id" : ObjectId("530824b95f44eac1068b45c0") }
{ "1" : { "relevancy" : [  "Y",  "Y" ] }, "_id" : ObjectId("530824b95f44eac1068b45c2") }
{ "1" : { "relevancy" : [  "N" ] }, "_id" : ObjectId("530824b95f44eac1068b45c3") }
{ "1" : { "relevancy" : [  "Y",  "Y" ] }, "_id" : ObjectId("530824b95f44eac1068b45c4") }
{ "1" : { "relevancy" : [  "Y",  "N" ] }, "_id" : ObjectId("530824b95f44eac1068b45c6") }
{ "1" : { "relevancy" : [  "N" ] }, "_id" : ObjectId("530824b95f44eac1068b45c7") }
{ "1" : { "relevancy" : [  "Y",  "N" ] }, "_id" : ObjectId("530824b95f44eac1068b45c8") }

Я хочу подсчитать количество строк, имеющих " Y "как последний элемент массива"релевантность". Сверху кода должно быть 3. Как это сделать. Пожалуйста, помогите мне.

1 ответов


как вы уже знаете,$slice используется только в проекции для ограничения элементов массива, возвращаемых в результатах. Таким образом, вы застряли бы с обработкой списка программно с результатами из find().

лучший подход-использовать совокупность. Но сначала давайте рассмотрим, как $slice используется:

> db.collection.find({},{ relevancy: {$slice: -1} })
{ "_id" : ObjectId("530824b95f44eac1068b45c0"), "relevancy" : [  "Y" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c2"), "relevancy" : [  "Y" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c3"), "relevancy" : [  "N" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c4"), "relevancy" : [  "Y" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c6"), "relevancy" : [  "N" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c7"), "relevancy" : [  "N" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c8"), "relevancy" : [  "N" ] }

таким образом, вы получаете последний элемент массива, но вы застряли с зацикливанием результатов, поскольку вы не можете матч значение последнего элемента. С таким же успехом вы могли сделать это в коде.

теперь давайте посмотрим на совокупность :

db.collection.aggregate([
    // Match things so we get rid of the documents that will never match, but it will
    // still keep some of course since they are arrays, that *may* contain "N"
    { "$match": { "relevancy": "Y" } },

    // De-normalizes the array
    { "$unwind": "$relevancy" },

    // The order of the array is retained, so just look for the $last by _id
    { "$group": { "_id": "$_id", "relevancy": { "$last": "$relevancy" } }},

    // Match only the records with the results you want
    { "$match": { "relevancy": "Y" }},

    // Oh, and maintain the original _id order [ funny thing about $last ]
    { "$sort": { "_id": 1 } }
])

даже если это будет ваше первое использование aggregate (), я призываю вас научиться. Это, пожалуй, самый полезный инструмент для решения проблем. Конечно, для меня. Поместите каждый шаг в после в то время, если вы изучаете.

также не уверен в вашем документе форма, все 1: { ... } обозначение поддокумента кажется ошибкой, но вы должны прояснить это или настроить код выше для ссылки "1.relevancy" вместо. Я надеюсь, что ваши документы на самом деле выглядят больше так:

{ "relevancy" : [  "Y" ] , "_id" : ObjectId("530824b95f44eac1068b45c0") }
{ "relevancy" : [  "Y",  "Y" ] , "_id" : ObjectId("530824b95f44eac1068b45c2") }
{ "relevancy" : [  "N" ], "_id" : ObjectId("530824b95f44eac1068b45c3") }
{ "relevancy" : [  "Y",  "Y" ], "_id" : ObjectId("530824b95f44eac1068b45c4") }
{ "relevancy" : [  "Y",  "N" ], "_id" : ObjectId("530824b95f44eac1068b45c6") }
{ "relevancy" : [  "N" ], "_id" : ObjectId("530824b95f44eac1068b45c7") }
{ "relevancy" : [  "Y",  "N" ], "_id" : ObjectId("530824b95f44eac1068b45c8") }

MongoDB 3.2.x и вверх

конечно MongoDB 3.2 вводит оператор "агрегации" для $slice и еще лучше $arrayElemAt оператор который извлекает потребность для любого $unwind и $group обработка. После первого $match запрос вы просто делаете "логический поединок" с $redact:

db.collection.aggregate([
    { "$match": { "relevancy": "Y" } },
    { "$redact": {
        "$cond": {
            "if": { "$eq": [{ "$arrayElemAt": [ "$relevancy", -1 ], "Y" ] },
            "then": "$$KEEP",
            "else": "$$PRUNE"
        }
    }}   
])

это будет делать проверку последнего элемента массива при принятии решения о том, следует ли $$KEEP или $$PRUNE документы из возвращенных результатов.

если вы все еще хотели "проекцию", то вы можете добавить $slice:

db.collection.aggregate([
    { "$match": { "relevancy": "Y" } },
    { "$redact": {
        "$cond": {
            "if": { "$eq": [{ "$arrayElemAt": [ "$relevancy", -1 ], "Y" ] },
            "then": "$$KEEP",
            "else": "$$PRUNE"
        }
    }},
    { "$project": { "relevancy": { "$slice": [ "$relevancy", -1 ] } } }
])

или альтернативный подход:

db.collection.aggregate([
    { "$match": { "relevancy": "Y" } },
    { "$project": { "relevancy": { "$slice": [ "$relevancy", -1 ] } } },
    { "$match": { "relevancy": "Y" } }
])

но, вероятно, менее дорого сделать $redact сначала и "затем" выполните любое переформирование в `$project.