MongoDB: получить последний элемент массива, если свойство существует - PullRequest
1 голос
/ 10 июля 2019

Я хотел бы объединить последний параметр с существующим значением.

Моя структура данных:

{
  _id: 1,
  ...(many other fields)...
  settings: [
    {
      _id: 11,
      values: [
        {
          likesFruit: true,
          likesMeat: true,
        }
      ] 
   },
   {
      _id: 12,
      values: [
        {
          likesFruit: false
        }
      ] 
    }
  ]
}, 
{
  _id: 2,
  ...(many other fields)...
  settings: [] // empty
}

Вопрос: Как получить этот результат

{
  _id: 1,
  ...(many other fields)...
  likesFruit: false,
  likesMeat: true
},
{
 _id: 2,
 ...(many other fields)...
}

Мне нужно решение, которое не удаляет результаты, где настройки, например, пусты / не содержат все реквизиты.Например, _id: 2 не содержит никаких настроек.Поэтому я не хочу его раскручивать и фильтровать для определенной настройки, потому что мне все еще нужен корневой объект, даже если настройки не существуют.

Я пробовал это с addFields:

$addFields: {
  likesFruit: "$settings.value.likesFruit",
  likesMeat: "$settings.value.likesMeat"
}

Что оставляет меня с этим:

_id: 1,
...(many other fields)...
settings: [...],
likesFruit: [[true], [false]]
likesMeat: [[], [true]]

Который я пытался отфильтровать с помощью:

$addFields: {
  likesFruit: {
    $filter: {
      input: "$likesMeat",
      as: "items",
      cond: { $ne : ["$$items", null ] }
    }
  }
}

Моя главная проблема - двойное вложение.Интересующее меня "settings.value" содержит только один объект.Поэтому я думаю, что переход от settings.values: [{}] к settings.values: {} был бы ключом к решению.Тогда я мог бы project отдельные значения, использовать $reverseArray и $arrayElemAt: [$array, 0], чтобы получить последний элемент.

1 Ответ

1 голос
/ 10 июля 2019

Вы можете воспользоваться оператором $ mergeObjects , поскольку, как указано в документации:

mergeObjects перезаписывает значения полей при объединении документов.Если документы для объединения содержат одно и то же имя поля, поле в результирующем документе будет иметь значение из последнего документа, слитого для поля.

Поскольку у вас есть вложенные массивы, вам нужно удвоить $ уменьшить , чтобы агрегировать ваши данные.Вы также можете использовать $ replaceRoot для продвижения ваших агрегированных значений на верхний уровень

db.col.aggregate([
    {
        $addFields: {
            settingsAggregated: {
                $reduce: {
                    input: "$settings",
                    initialValue: {},
                    in: {
                        $mergeObjects: [ "$$value", 
                            { $reduce: { input: "$$this.values", initialValue: {}, in: { $mergeObjects: [ "$$value", "$$this" ] } } }
                        ]
                    }
                }
            }
        }
    },
    {
        $replaceRoot: {
            newRoot: {
                $mergeObjects: [ "$$ROOT", "$settingsAggregated" ]
            }
        }
    },
    {
        $project: {
            settings: 0,
            settingsAggregated: 0
        }
    }
])

Mongo Playground

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...