Как я могу (в MongoDB) объединить данные из нескольких коллекций в одну коллекцию?
Могу ли я использовать map-Reduce и если да, то как?
Я был бы очень признателен за пример, так как я новичок.
mongodb
mongodb-query
aggregation-framework
user697697
источник
источник
db.collection1.find().forEach(function(doc){db.collection2.save(doc)});
, достаточно. Пожалуйста, укажите используемый драйвер (java, php, ...), если вы не используете оболочку mongo.Ответы:
Несмотря на то, что вы не можете сделать это в режиме реального времени, вы можете запустить map-Reduction несколько раз, чтобы объединить данные, используя опцию «Reduce» Out в MongoDB 1.8+ map / проводить (см. Http://www.mongodb.org/ display / DOCS / MapReduce # MapReduce-Outputoptions ). У вас должен быть какой-то ключ в обеих коллекциях, который вы можете использовать как _id.
Например, допустим, у вас есть
users
коллекция иcomments
коллекция, и вы хотите иметь новую коллекцию, в которой есть демографические данные для каждого комментария.Допустим,
users
коллекция имеет следующие поля:И тогда в
comments
коллекции есть следующие поля:Вы бы сделали эту карту / уменьшить:
На этом этапе у вас будет новая коллекция под названием,
users_comments
которая содержит объединенные данные, и теперь вы можете использовать ее. Все эти уменьшенные коллекции имеют_id
ключ, который вы выдавали в функциях карты, и тогда все значения являются подобъектом внутриvalue
ключа - значения не находятся на верхнем уровне этих сокращенных документов.Это несколько простой пример. Вы можете повторить это с большим количеством коллекций, сколько хотите, чтобы создать сокращенную коллекцию. Вы также можете сделать резюме и агрегацию данных в процессе. Вероятно, вы бы определили более одной функции сокращения, поскольку логика для агрегирования и сохранения существующих полей становится более сложной.
Вы также заметите, что теперь существует один документ для каждого пользователя со всеми комментариями этого пользователя в массиве. Если бы мы объединяли данные, которые имеют отношение один-к-одному, а не один-ко-многим, это было бы плоско, и вы могли бы просто использовать функцию сокращения, например так:
Если вы хотите сгладить
users_comments
коллекцию, чтобы она содержала один документ на комментарий, дополнительно запустите:Эта техника определенно не должна выполняться на лету. Он подходит для работы cron или чего-то подобного, который периодически обновляет объединенные данные. Вы, вероятно, захотите запустить
ensureIndex
новую коллекцию, чтобы убедиться, что запросы, которые вы выполняете против нее, выполняются быстро (имейте в виду, что ваши данные все еще находятся внутриvalue
ключа, поэтому, если вы захотите проиндексироватьcomments_with_demographics
время комментарияcreated
, это будетdb.comments_with_demographics.ensureIndex({"value.created": 1});
источник
users_comments
коллекции после первого блока кода gist.github.com/nolanamy/83d7fb6a9bf92482a1c4311ad9c78835MongoDB 3.2 теперь позволяет объединять данные из нескольких коллекций в одну через этап агрегации $ lookup . В качестве практического примера предположим, что у вас есть данные о книгах, разделенных на две разные коллекции.
Первый сбор называется
books
, имея следующие данные:И называется вторая коллекция
books_selling_data
, имеющая следующие данные:Чтобы объединить обе коллекции, достаточно использовать $ lookup следующим образом:
После этой агрегации
books
коллекция будет выглядеть следующим образом:Важно отметить несколько вещей:
books_selling_data
не может быть очищена.Итак, в заключение, если вы хотите объединить обе коллекции, имея в данном случае плоское поле copy_sold с общим количеством проданных копий, вам придется работать немного больше, возможно, с использованием промежуточной коллекции, которая затем быть $ до окончательной коллекции.
источник
$lookup
не все ли "localField" и "foreignField" равны "isbn"? не "_id", а "isbn"?Если нет массовой вставки в mongodb, мы зациклим все объекты в
small_collection
и вставим их один за другим вbig_collection
:источник
Очень простой пример с $ lookup.
Здесь используется
Вместо того
Потому что {$ unwind: "$ userRoleData"} возвращает пустой или 0 результат, если не найдена соответствующая запись с $ lookup.
источник
Создание объединений в MongoDB в режиме «SQL UNION» возможно с использованием агрегации и поиска в одном запросе. Вот пример, который я протестировал, который работает с MongoDB 4.0:
Вот объяснение того, как это работает:
Создайте
aggregate
из любой коллекции вашей базы данных, в которой есть хотя бы один документ. Если вы не можете гарантировать, что любая коллекция вашей базы данных не будет пустой, вы можете обойти эту проблему, создав в своей базе данных своего рода «фиктивную» коллекцию, содержащую один пустой документ, который будет там специально для выполнения запросов объединения.Сделайте первый этап вашего конвейера, чтобы быть
{ $limit: 1 }
. Это лишит все документы коллекции кроме первого.Удалите все поля оставшегося документа, используя
$project
этап:Ваш агрегат теперь содержит один пустой документ. Пришло время добавить поиск для каждой коллекции, которую вы хотите объединить вместе. Вы можете использовать
pipeline
поле , чтобы сделать некоторые конкретные фильтрации, или оставитьlocalField
иforeignField
в нуле , чтобы соответствовать всей коллекции.Теперь у вас есть агрегат, содержащий один документ, который содержит 3 массива, например:
Затем вы можете объединить их в один массив, используя
$project
этап вместе с$concatArrays
оператором агрегирования:Теперь у вас есть агрегат, содержащий один документ, в котором расположен массив, содержащий ваше объединение коллекций. Что еще предстоит сделать , это добавить
$unwind
и на$replaceRoot
сцену , чтобы разделить ваш массив на отдельные документы:Вуаля. Теперь у вас есть набор результатов, содержащий коллекции, которые вы хотите объединить вместе. Затем вы можете добавить дополнительные этапы для дальнейшей фильтрации, сортировки, применения skip () и limit (). Практически все, что вы хотите.
источник
использовать несколько $ lookup для нескольких коллекций в агрегации
запрос:
результат:
источник
Mongorestore имеет эту функцию добавления поверх того, что уже есть в базе данных, поэтому это поведение можно использовать для объединения двух коллекций:
Пока не пробовал, но он может работать быстрее, чем подход "карта / уменьшение".
источник
Начнем с того
Mongo 4.4
, что мы можем достичь этого объединения в конвейере агрегации, связав новый$unionWith
этап агрегации с$group
новым$accumulator
оператором:$unionWith
объединяет записи из данной коллекции в документы, уже находящиеся в конвейере агрегации. После двух этапов объединения у нас есть все пользователи, книги и записи фильмов в конвейере.Затем мы
$group
регистрируем$user
и накапливаем элементы, используя$accumulator
оператор, позволяющий настраивать накопления документов по мере их группировки:accumulateArgs
.init
определяет состояние, которое будет накапливаться при группировании элементов.accumulate
функция позволяет выполнять пользовательские действия с записью группируется, чтобы построить накопленное состояние. Например, если для сгруппированного элементаbook
определено поле, мы обновляемbooks
часть состояния.merge
используется для объединения двух внутренних состояний. Он используется только для агрегатов, работающих на сегментированных кластерах или когда операция превышает пределы памяти.источник
Да, вы можете: Возьмите эту служебную функцию, которую я написал сегодня:
Вы можете передать в эту функцию любое количество коллекций, первая из которых будет целевой. Все остальные коллекции являются источниками, которые необходимо перенести в целевой.
источник
Фрагмент кода. Courtesy-Несколько сообщений о переполнении стека, включая этот.
источник
Вы должны сделать это на уровне приложения. Если вы используете ORM, он может использовать аннотации (или что-то подобное) для извлечения ссылок, которые существуют в других коллекциях. Я работал только с Morphia , и
@Reference
аннотация извлекает ссылочную сущность при запросе, поэтому я могу избежать делать это самостоятельно в коде.источник