Агрегация MongoDB — $filter в проекции для встроенных массивов

#arrays #mongodb #aggregation-framework #projection

#массивы #mongodb #агрегация-фреймворк #проекция

Вопрос:

У меня сложная структура объекта JSON, которая содержит (N) количество встроенных массивов. Одна запись — это объект с двумя полями : @name и content . Мне нужно отфильтровать их на этапе проектирования (без использования $unwind ), чтобы получить один конкретный объект, где @name поле равно определенному значению:

a

  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 местах для поиска. как я уже прокомментировал в коде.