#arrays #mongodb #aggregation-framework #projection
#массивы #mongodb #агрегация-фреймворк #проекция
Вопрос:
У меня сложная структура объекта JSON, которая содержит (N) количество встроенных массивов. Одна запись — это объект с двумя полями : @name
и content
. Мне нужно отфильтровать их на этапе проектирования (без использования $unwind
), чтобы получить один конкретный объект, где @name
поле равно определенному значению:
productCategory: {$filter: {
input: '$characteristics.attributeGroup.attribute',
as: 'attribute',
cond: {
...?
}}
$characteristics.attributeGroup.attribute
Входные данные возвращают указанную выше структуру. Я пытался использовать что-то подобное, $cond: { $eq: ['$$attribute.@name', 'averageRating'] }
но это не работает.
Не могли бы вы помочь мне найти решение здесь?
Заранее спасибо!
Комментарии:
1. можете ли вы добавить несколько примеров документов вместо изображения и как вы хотите получить ожидаемый результат? в объекте или массиве?
2. Это пример содержимого json: pastebin.com/8er3iPMB Ожидаемым результатом будет просто объект с этим искомым именем или, по крайней мере, массив с одной записью. например: атрибут: { «@name»: «attributeKey2», «content»: «attributeValue2» }
3. Значение атрибута @name является уникальным. Не может быть повторено в любом другом массиве / объекте
4. Не могли бы вы добавить ожидаемый результат? Это упростило бы задачу
Ответ №1:
Вы можете попробовать,
$reduce
для повторения циклаattributeGroup
массива и обратного слияния объектов с помощью$mergeObjects
- проверьте условие, если тип атрибута
object
равен, затем снова проверьте второе условие, если @name совпадает, затем верните значения, в противном случае перейдите к другому условию $reduce
чтобы повторить циклattribute
массива, проверьте условие, если имя совпадает, затем верните значение
let name = "Artikelhinweise";
db.collection.aggregate([
{ $match: { "attributeGroup.attribute.@name": name } }, // name pass here
{
$project: {
attributeGroup: {
$reduce: {
input: "$attributeGroup",
initialValue: {},
in: {
$mergeObjects: [
"$value",
{
$cond: [
{ $eq: [{ $type: "$this.attribute" }, "object"] },
{
$cond: [
{ $eq: ["$this.attribute.@name", name] }, // name pass here
{
"@name": "$this.attribute.@name",
"content": "$this.attribute.content"
},
"$value"
]
},
{
$reduce: {
input: "$this.attribute",
initialValue: {},
in: {
$cond: [
{ $eq: ["$this.@name", name] }, // name pass here
{
"@name": "$this.@name",
"content": "$this.content"
},
"$value"
]
}
}
}
]
}
]
}
}
}
}
}
])
Комментарии:
1. Привет, Турившал! Спасибо за ваш ответ. Я попытался применить этот этап к большему количеству «подобных» данных. Кажется, что структура немного более встроена, чем я ожидал. Я создал новую конфигурацию в mongo playground: mongoplayground.net/p/m9mwDIeXWRn Этот массив верхнего уровня является предыдущим значением «productAttributes», но, похоже, существуют дополнительные массивы attributeGroup :/ Остальное то же самое, включая поля @ name и content в объектах, но после исследования я все еще не смог извлечь ни одного поля с помощью Produktbasisklasseв поле @ name
2. В некоторых документах
attribute
поле является объектом, а в некоторых — его массивом, это правильные данные илиattribute
поле, имеющее оба типа данных?3. это правильно. Если существует более 1 атрибута — это массив, но только для одного — объекта json :/
4. я обновил ответ и ссылку на игровую площадку, можете проверить. вам нужно передать значение имени в 3 местах для поиска. как я уже прокомментировал в коде.