использование оператора $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.