У меня около 50 тысяч документов со множеством полей, но важные для этой проблемы выглядят так:
"_id": ObjectId(""),
...
"item": "apple"
"properties" : [
{
"color": "red",
"size" : "L",
"status": "eatable"
}
],
...
Я пытаюсь напечатать строки, которые выглядят как item+";"+properties.color, сохраняя при этом целостность имеющихся у меня данных и печатая эти поля только для определенных документов. На данный момент единственное, что мне удалось, - это распечатать либо только элемент, либо весь массив «свойств», но я не могу получить ни два из них одновременно, ни только цвет.
db.getCollection("foods").find({properties:{$elemMatch:{color: {$in:["red", "green", "orange", "blue"]}}}})
.aggregate([
{ $unwind: {path:"$properties", preserveNullAndEmptyArrays: true}},
]).forEach(function(row){
if (row.properties !== undefined) print (row.item + ";" + row.properties.color) })
Это дает ошибку из-за поиска перед агрегатом, но я действительно не знаю, как еще это сделать, чтобы он печатал это только для тех строк, которые соответствуют этому условию (и я также не знаю, есть ли $ unwind испортит массивы в моих данных, или это просто временное «разделение» во время работы функции).
Что я сейчас делаю, получая только предметы:
db.getCollection("foods").find({properties:{$elemMatch:{color: {$in:["red", "green", "orange", "blue"]}}}})
.forEach(
function(row){
print (row.item)
}
)
Изменив row.item на row.properties, я напечатал полные массивы, но добавление .color после этого ничего не дало.
Не уверен, что я понял, но как насчет подготовки данных в запрос следующим образом:
db.getCollection("foods").aggregate([
{
$match: {
"properties.color": {
$in: [
"red",
"green",
"orange",
"blue"
]
}
}
},
{
$project: {
_id: 0
item: 1,
color: {
"$arrayElemAt": [
"$properties.color",
0
]
}
}
}
])
Пример здесь.
И получив что-то вроде этого JSON ниже, вы можете легко перебирать и получить доступ к свойствам color
и item
:
[
{
"color": "red",
"item": "apple"
}
]
Спасибо, кажется, это работает! Есть ли способ распечатать полученную проекцию? Я пытаюсь скопировать результаты, но к тому времени, когда я пытаюсь загрузить третью страницу результатов в studio3t, я получаю тайм-аут или сообщение, что результат был очищен из кеша, и мне нужно снова выполнить запрос.
нвм. Я получил это, присвоив агрегат переменной (пусть result = db.getCollection...), а затем с помощью forEach напечатав переменную «result». Еще раз спасибо!
Вы правы, используя
find
иaggregate
как один запрос — это ошибка. Я предлагаю использовать агрегатный запрос с$unwind
в поле массива, затем$match
для фильтрации поля"properties.color"
(для сопоставления нескольких цветов используйте оператор$in
) и, наконец, закончить этапом$project
или$addFields
для проецирования и форматирования полей.