Как объединить все поля массива документов вместе в MongoDB?

#javascript #node.js #mongodb

Вопрос:

Как объединить поле массива всех документов вместе в MongoDB?

Например:

Моя коллекция содержит эти документы:

 [
  {
    _id: 0,
    categories: ['a', 'b', 'c'],
  },
  {
    _id: 1,
    categories: ['d', 'e', 'f'],
  },
  {
    _id: 2,
    categories: ['g', 'h', 'i'],
  },
];
 

И результат должен быть:

 ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
 

Комментарии:

1. data.flatMap это хорошее место для начала

2. Как вы можете видеть, мы не знаем, хотите ли вы использовать JavaScript или решение Mongo

Ответ №1:

Лучший способ сделать это-использовать различные

 db.collection.distinct('categories')
 

Если результаты превышают 16 МБ, то вы можете использовать только $unwind и $group в агрегированном виде:

 db.collection.aggregate([
    {
        $unwind: "$categories"
    },
    {
        $group: {
            _id: "$categories"
        }
    }
])
 

Комментарии:

1. Ваш агрегированный запрос не возвращает желаемый результат: пример

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

3. Да, это верно, но OP ожидает массив строк, а не массив объектов.

4. он не сказал, что я думаю, что он хочет уникальных результатов

Ответ №2:

Вы можете $unwind и $group вам это понравится:

 db.collection.aggregate([
  {
    "$unwind": "$categories"
  },
  {
    "$group": {
      "_id": null,
      "categories": {
        "$push": "$categories"
      }
    }
  }
])
 

Пример здесь

Ответ №3:

   const list = [
    {
      _id: 0,
      categories: ["a", "b", "c"],
    },
    {
      _id: 1,
      categories: ["d", "e", "f"],
    },
    {
      _id: 2,
      categories: ["g", "h", "i"],
    },
  ];
  let newList = list.map((item) => [...item.categories]);
  let finalList = newList.reduce((a, b) => [...a, ...b]);
 

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

Ответ №4:

Если вы спрашиваете о JS, я бы использовал метод сокращения:

 const res = [
  {
    _id: 0,
    categories: ['a', 'b', 'c'],
  },
  {
    _id: 1,
    categories: ['d', 'e', 'f'],
  },
  {
    _id: 2,
    categories: ['g', 'h', 'i'],
  },
].reduce((acc, current) => ([...acc, ...current.categories]), [])

console.log(res) 

Ответ №5:

Ниже приведены 2 способа сделать это, не удаляя дубликаты, потому что я думаю, что вам нужны все значения.

Запрос (решение JF лучше, чем это, но это альтернативный способ)
(Оба запроса работают, если конечный массив категорий

Тестовый код здесь

 db.collection.aggregate([
  {
    "$group": {
      "_id": null,
      "categories": {
        "$push": "$categories"
      }
    }
  },
  {
    "$project": {
      "_id": 0
    }
  },
  {
    "$set": {
      "categories": {
        "$reduce": {
          "input": "$categories",
          "initialValue": [],
          "in": {
            "$concatArrays": [
              "$value",
              "$this"
            ]
          }
        }
      }
    }
  }
])
 

ВОЗВРАТ

 [
  {
    "categories": [
      "a",
      "b",
      "c",
      "d",
      "e",
      "f",
      "g",
      "h",
      "i"
    ]
  }
]
 

Запрос 2
(если категории > 16 МБ)

Тестовый код здесь

 db.collection.aggregate([
  {
    "$unwind": {
      "path": "$categories"
    }
  },
  {
    "$unset": [
      "_id"
    ]
  }
])
 

ВОЗВРАТ

 [
  {
    "categories": "a"
  },
  {
    "categories": "b"
  },
  {
    "categories": "c"
  },
  {
    "categories": "d"
  },
  {
    "categories": "e"
  },
  {
    "categories": "f"
  },
  {
    "categories": "g"
  },
  {
    "categories": "h"
  },
  {
    "categories": "i"
  }
]