Как выполнить эквивалент SQL Join в MongoDB?

498

Как выполнить эквивалент SQL Join в MongoDB?

Например, скажем, у вас есть две коллекции (пользователи и комментарии), и я хочу получить все комментарии с pid = 444 вместе с информацией о пользователях для каждой.

comments
  { uid:12345, pid:444, comment="blah" }
  { uid:12345, pid:888, comment="asdf" }
  { uid:99999, pid:444, comment="qwer" }

users
  { uid:12345, name:"john" }
  { uid:99999, name:"mia"  }

Есть ли способ получить все комментарии с определенным полем (например, ... find ({pid: 444})) и информацию о пользователе, связанную с каждым комментарием, за один раз?

В данный момент я сначала получаю комментарии, которые соответствуют моим критериям, затем вычисляю все uid в этом наборе результатов, получаю пользовательские объекты и объединяю их с результатами комментария. Похоже, я делаю это неправильно.

Неизвестный
источник
35
Последний ответ на этот вопрос, вероятно, является наиболее актуальным, поскольку MongoDB 3.2+ реализовал решение для соединения под названием $ lookup. Думал, что я бы толкнул это здесь, потому что, возможно, не все будут читать до дна. stackoverflow.com/a/33511166/2593330
thefourtheye
6
Правильно, $ lookup был представлен в MongoDB 3.2. Подробности можно найти по адресу docs.mongodb.org/master/reference/operator/aggregation/lookup/…
NDB

Ответы:

306

Начиная с версии 3.2, ответы на этот вопрос в основном уже не верны. Новый оператор $ lookup, добавленный в конвейер агрегации, по сути идентичен левому внешнему соединению:

https://docs.mongodb.org/master/reference/operator/aggregation/lookup/#pipe._S_lookup

Из документов:

{
   $lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }
}

Конечно, Mongo не является реляционной базой данных, и разработчики стараются рекомендовать конкретные варианты использования для $ lookup, но, по крайней мере, начиная с 3.2, теперь возможно объединение с MongoDB.

Клейтон Гулик
источник
@clayton: Как насчет более двух коллекций?
Дипен Дедания
1
@DipenDedania просто добавьте дополнительные этапы поиска $ в конвейер агрегации.
Клейтон Гулик
Я не могу присоединиться к любому полю массива в левой коллекции с соответствующим идентификатором в правой коллекции. Кто-нибудь может мне помочь ??
Пратик Сингх
1
Меня это немного смущает - есть ли способ указать, что вы хотите, чтобы в коллекции «from» были только определенные документы, или она автоматически объединяет все в БД одновременно?
user3413723
Просто интересно, есть ли последняя версия Spring Data MongoDB с поддержкой 3.2?
gtiwari333
142

Эта страница на официальном сайте mongodb посвящена именно этому вопросу:

https://mongodb-documentation.readthedocs.io/en/latest/ecosystem/tutorial/model-data-for-ruby-on-rails.html

Когда мы показываем наш список историй, нам нужно показать имя пользователя, который разместил историю. Если бы мы использовали реляционную базу данных, мы могли бы выполнить объединение пользователей и хранилищ и получить все наши объекты в одном запросе. Но MongoDB не поддерживает объединения и поэтому иногда требует некоторой денормализации. Здесь это означает кэширование атрибута username.

Реляционные пуристы могут уже чувствовать себя неловко, как если бы мы нарушали какой-то универсальный закон. Но давайте иметь в виду, что коллекции MongoDB не эквивалентны реляционным таблицам; каждый служит уникальной цели дизайна. Нормализованная таблица обеспечивает атомарный, изолированный кусок данных. Документ, однако, более близко представляет объект в целом. В случае сайта социальных новостей можно утверждать, что имя пользователя является неотъемлемой частью публикуемой истории.

Уильям Стейн
источник
51
@dudelgrincen это смена парадигмы от нормализации и реляционных баз данных. Цель NoSQL - очень быстро читать и писать из базы данных. С BigData у вас будет множество приложений и серверов переднего плана с меньшим числом в БД. Вы должны делать миллионы транзакций в секунду. Выгрузите тяжелую работу из базы данных и перенесите ее на уровень приложения. Если вам нужен глубокий анализ, вы запускаете задание интеграции, которое помещает ваши данные в базу данных OLAP. В любом случае, вы не должны получать много глубоких запросов от ваших баз данных OLTP.
Snowburnt
18
@dudelgrincen Я должен также сказать, что это не для каждого проекта или дизайна. Если у вас есть что-то, что работает в базе данных типа SQL, зачем это менять? Если вы не можете массировать свою схему для работы с noSQL, тогда не делайте этого.
Snowburnt
9
Миграции и постоянно развивающиеся схемы также намного легче управлять в системе NoSQL.
Джастин
14
Что, если у пользователя 3,540 сообщений на сайте, и он меняет свое имя пользователя в профиле? Следует ли обновлять каждое сообщение новым именем пользователя?
Иво Перейра
2
@IvoPereira Да, и именно поэтому следует избегать моделирования данных таким образом. Есть статья, которая объясняет тот же сценарий и его последствия: почему вы никогда не должны использовать MongoDB
Омид
138

Мы можем объединить / объединить все данные только в одной коллекции с помощью простой функции в несколько строк с помощью клиентской консоли mongodb, и теперь мы можем выполнить требуемый запрос. Ниже полный пример,

.- Авторы:

db.authors.insert([
    {
        _id: 'a1',
        name: { first: 'orlando', last: 'becerra' },
        age: 27
    },
    {
        _id: 'a2',
        name: { first: 'mayra', last: 'sanchez' },
        age: 21
    }
]);

.- Категории:

db.categories.insert([
    {
        _id: 'c1',
        name: 'sci-fi'
    },
    {
        _id: 'c2',
        name: 'romance'
    }
]);

.- Книги

db.books.insert([
    {
        _id: 'b1',
        name: 'Groovy Book',
        category: 'c1',
        authors: ['a1']
    },
    {
        _id: 'b2',
        name: 'Java Book',
        category: 'c2',
        authors: ['a1','a2']
    },
]);

.- Книжное кредитование

db.lendings.insert([
    {
        _id: 'l1',
        book: 'b1',
        date: new Date('01/01/11'),
        lendingBy: 'jose'
    },
    {
        _id: 'l2',
        book: 'b1',
        date: new Date('02/02/12'),
        lendingBy: 'maria'
    }
]);

.- Магия:

db.books.find().forEach(
    function (newBook) {
        newBook.category = db.categories.findOne( { "_id": newBook.category } );
        newBook.lendings = db.lendings.find( { "book": newBook._id  } ).toArray();
        newBook.authors = db.authors.find( { "_id": { $in: newBook.authors }  } ).toArray();
        db.booksReloaded.insert(newBook);
    }
);

.- Получить новые данные коллекции:

db.booksReloaded.find().pretty()

.- Отклик :)

{
    "_id" : "b1",
    "name" : "Groovy Book",
    "category" : {
        "_id" : "c1",
        "name" : "sci-fi"
    },
    "authors" : [
        {
            "_id" : "a1",
            "name" : {
                "first" : "orlando",
                "last" : "becerra"
            },
            "age" : 27
        }
    ],
    "lendings" : [
        {
            "_id" : "l1",
            "book" : "b1",
            "date" : ISODate("2011-01-01T00:00:00Z"),
            "lendingBy" : "jose"
        },
        {
            "_id" : "l2",
            "book" : "b1",
            "date" : ISODate("2012-02-02T00:00:00Z"),
            "lendingBy" : "maria"
        }
    ]
}
{
    "_id" : "b2",
    "name" : "Java Book",
    "category" : {
        "_id" : "c2",
        "name" : "romance"
    },
    "authors" : [
        {
            "_id" : "a1",
            "name" : {
                "first" : "orlando",
                "last" : "becerra"
            },
            "age" : 27
        },
        {
            "_id" : "a2",
            "name" : {
                "first" : "mayra",
                "last" : "sanchez"
            },
            "age" : 21
        }
    ],
    "lendings" : [ ]
}

Я надеюсь, что эти строки могут помочь вам.

Орландо Бесерра
источник
2
мне интересно, можно ли запустить этот же код с помощью доктрины mongodb?
abbood
4
Что происходит, когда один из ссылочных объектов получает обновление? Это обновление автоматически отражается в объекте книги? Или этот цикл нужно запустить снова?
Балуптон
14
Это хорошо, если ваши данные невелики. Он будет приносить содержание каждой книги вашему клиенту, а затем извлекать каждую категорию, кредитование и авторов по одному. В тот момент, когда ваши книги исчисляются тысячами, это будет очень медленно. Вероятно, лучшим способом было бы использовать конвейер агрегации и выводить объединенные данные в отдельную коллекцию. Позвольте мне вернуться к этому снова. Я добавлю, что ответ.
Сандип Гири
Можете ли вы адаптировать свой алгоритм к этому другому примеру? stackoverflow.com/q/32718079/287948
Питер Краусс
1
@SandeepGiri Как я могу сделать агрегатный конвейер, так как у меня действительно очень интенсивные данные в отдельном сборе нужно объединить?
Яссин Абдул-Рахман
38

Вы должны сделать это так, как вы описали. MongoDB является нереляционной базой данных и не поддерживает объединения.

Отто Альмендингер
источник
4
Кажется неправильным в плане производительности, если исходить из опыта работы с сервером sql, но, возможно, не так уж и плохо с документом db?
terjetyl
3
Кроме того, я хотел бы, чтобы MongoDB взяла «набор результатов» (с выбранными возвращаемыми полями) в качестве входных данных для нового запроса за один раз, очень похоже на вложенные запросы в SQL
Стейн Сандерс,
1
@terjetyl Вы должны действительно планировать это. Какие поля вы собираетесь представлять во внешнем интерфейсе, если в отдельном представлении их количество ограничено, вы принимаете их за внедренные документы. Ключ заключается в том, чтобы не нужно делать соединения. Если вы хотите сделать глубокий анализ, вы делаете это после факта в другой базе данных. Запустите задание, которое преобразует данные в куб OLAP для оптимальной производительности.
Snowburnt
4
Начиная с версии mongo 3.2 поддерживаются левые соединения.
Сомнат Мулук
18

Как уже отмечали другие, вы пытаетесь создать реляционную базу данных из не реляционной базы данных, которую вы действительно не хотите делать, но в любом случае, если у вас есть такой случай, вам нужно использовать это решение. Сначала мы делаем поиск foreach в коллекции A (или в вашем случае пользователей), а затем мы получаем каждый элемент как объект, затем мы используем свойство объекта (в вашем случае uid) для поиска во второй коллекции (в комментариях к вашему случаю), если мы может найти его, тогда у нас есть совпадение, и мы можем напечатать или сделать что-то с ним. Надеюсь, это поможет вам и удачи :)

db.users.find().forEach(
function (object) {
    var commonInBoth=db.comments.findOne({ "uid": object.uid} );
    if (commonInBoth != null) {
        printjson(commonInBoth) ;
        printjson(object) ;
    }else {
        // did not match so we don't care in this case
    }
});
grepit
источник
Разве это не найти предмет, на котором мы сейчас работаем?
Скарлински
18

С правильной комбинацией $ lookup , $ project и $ match вы можете объединять несколько таблиц по нескольким параметрам. Это потому, что они могут быть связаны несколько раз.

Предположим, мы хотим сделать следующее ( ссылка )

SELECT S.* FROM LeftTable S
LEFT JOIN RightTable R ON S.ID =R.ID AND S.MID =R.MID WHERE R.TIM >0 AND 
S.MOB IS NOT NULL

Шаг 1: связать все таблицы

Вы можете найти столько таблиц, сколько захотите.

$ lookup - по одному для каждой таблицы в запросе

$ размотки - потому что данные корректно денормализованы, иначе они обернуты в массивы

Код Python ..

db.LeftTable.aggregate([
                        # connect all tables

                        {"$lookup": {
                          "from": "RightTable",
                          "localField": "ID",
                          "foreignField": "ID",
                          "as": "R"
                        }},
                        {"$unwind": "R"}

                        ])

Шаг 2. Определите все условия

$ проект : определите здесь все условные операторы, а также все переменные, которые вы хотите выбрать.

Код Python ..

db.LeftTable.aggregate([
                        # connect all tables

                        {"$lookup": {
                          "from": "RightTable",
                          "localField": "ID",
                          "foreignField": "ID",
                          "as": "R"
                        }},
                        {"$unwind": "R"},

                        # define conditionals + variables

                        {"$project": {
                          "midEq": {"$eq": ["$MID", "$R.MID"]},
                          "ID": 1, "MOB": 1, "MID": 1
                        }}
                        ])

Шаг 3: Присоединяйся ко всем условностям

$ match - объединить все условия, используя OR или AND и т. д. Их может быть несколько.

$ project : отменить все условия

Код Python ..

db.LeftTable.aggregate([
                        # connect all tables

                        {"$lookup": {
                          "from": "RightTable",
                          "localField": "ID",
                          "foreignField": "ID",
                          "as": "R"
                        }},
                        {"$unwind": "$R"},

                        # define conditionals + variables

                        {"$project": {
                          "midEq": {"$eq": ["$MID", "$R.MID"]},
                          "ID": 1, "MOB": 1, "MID": 1
                        }},

                        # join all conditionals

                        {"$match": {
                          "$and": [
                            {"R.TIM": {"$gt": 0}}, 
                            {"MOB": {"$exists": True}},
                            {"midEq": {"$eq": True}}
                        ]}},

                        # undefine conditionals

                        {"$project": {
                          "midEq": 0
                        }}

                        ])

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

sbharti
источник
17

Вот пример «объединения» * коллекций актеров и фильмов :

https://github.com/mongodb/cookbook/blob/master/content/patterns/pivot.txt

Это использует .mapReduce()метод

* join - альтернатива объединению в документно-ориентированных базах данных

противоядный
источник
19
-1, это НЕ объединяет данные из двух коллекций. Он использует данные из одной коллекции (актеров), которые вращают данные вокруг. Так что вещи, которые были ключами, теперь являются значениями, а значения теперь являются ключами ... сильно отличающимися от JOIN.
Эван Теран
12
Это именно то, что вам нужно сделать, MongoDB не реляционная, а ориентированная на документы. MapReduce позволяет играть с данными с большой производительностью (вы можете использовать кластер и т. Д.), Но даже для простых случаев это очень полезно!
Томас Деко
14

Вы можете объединить две коллекции в Mongo, используя поиск, который предлагается в версии 3.2. В вашем случае запрос будет

db.comments.aggregate({
    $lookup:{
        from:"users",
        localField:"uid",
        foreignField:"uid",
        as:"users_comments"
    }
})

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

db.users.aggregate({
    $lookup:{
        from:"comments",
        localField:"uid",
        foreignField:"uid",
        as:"users_comments"
    }
})

Это будет работать так же, как левое и правое соединение в SQL.

Джарри Яфери
источник
11

Это зависит от того, что вы пытаетесь сделать.

В настоящее время она настроена как нормализованная база данных, и это хорошо, и то, как вы это делаете, подходит.

Однако есть и другие способы сделать это.

У вас может быть коллекция постов, в которой есть встроенные комментарии для каждого поста со ссылками на пользователей, которых вы можете запросить итеративно. Вы можете хранить имя пользователя с комментариями, вы можете хранить их все в одном документе.

Суть в NoSQL заключается в том, что он предназначен для гибких схем и очень быстрого чтения и записи. В типичной ферме больших данных база данных является самым узким местом, у вас меньше механизмов баз данных, чем у приложений и серверов переднего плана ... они более дорогие, но более мощные, а также пространство на жестком диске сравнительно дешево. Нормализация исходит из концепции попыток сэкономить пространство, но она требует затрат на выполнение ваших баз данных для выполнения сложных объединений и проверки целостности отношений, выполнения каскадных операций. Все это избавляет разработчиков от головной боли, если они правильно спроектировали базу данных.

В NoSQL, если вы согласны с тем, что избыточность и пространство хранения не являются проблемами из-за их стоимости (как из-за процессорного времени, необходимого для обновления, так и из-за затрат на жесткий диск для хранения дополнительных данных), денормализация не является проблемой (для встроенных массивов, которые становятся Для сотен тысяч предметов это может быть проблемой производительности, но в большинстве случаев это не проблема). Кроме того, у вас будет несколько серверов приложений и серверов переднего плана для каждого кластера баз данных. Пусть они сделают тяжелую работу по объединению и позволят серверам баз данных придерживаться чтения и записи.

TL; DR: То, что вы делаете, хорошо, и есть другие способы сделать это. Посмотрите шаблоны моделей данных документации mongodb для некоторых замечательных примеров. http://docs.mongodb.org/manual/data-modeling/

Snowburnt
источник
8
«Нормализация проистекает из концепции попыток сэкономить место». Я подвергаю сомнению это. ИМХО нормализация происходит от концепции избежания избыточности. Скажем, вы храните имя пользователя вместе с постом в блоге. Что если она выйдет замуж? В ненормализованной модели вам придется просмотреть все сообщения и изменить название. В нормализованной модели вы обычно меняете ОДНУ запись.
DanielKhan
@DanielKhan - предотвращение избыточности и экономия места - схожие концепции, но я согласен с тем, что при повторном анализе избыточность является основной причиной этого проекта. Я перефразирую Спасибо за примечание.
Snowburnt
11

Существует спецификация, которую поддерживают многие драйверы, которая называется DBRef.

DBRef - более формальная спецификация для создания ссылок между документами. DBRefs (как правило) включают имя коллекции, а также идентификатор объекта. Большинство разработчиков используют DBRef только в том случае, если коллекция может перейти от одного документа к другому. Если ваша ссылочная коллекция всегда будет одинаковой, ссылки, приведенные выше, более эффективны.

Взято из документации MongoDB: Модели данных> Справочник по моделям данных> Ссылки на базы данных

Pickels
источник
11

$ lookup (агрегат)

Выполняет левое внешнее объединение с неотмеченной коллекцией в той же базе данных для фильтрации документов из «объединенной» коллекции для обработки. К каждому входному документу этап поиска $ добавляет новое поле массива, элементами которого являются совпадающие документы из «объединенной» коллекции. Этап поиска $ передает эти измененные документы на следующий этап. Этап $ lookup имеет следующие синтаксисы:

Равенство Матч

Чтобы выполнить сравнение на равенство между полем из входных документов и полем из документов «объединенной» коллекции, этап $ lookup имеет следующий синтаксис:

{
   $lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }
}

Операция будет соответствовать следующему псевдо-SQL-выражению:

SELECT *, <output array field>
FROM collection
WHERE <output array field> IN (SELECT <documents as determined from the pipeline>
                               FROM <collection to join>
                               WHERE <pipeline> );

Монго URL

GoutamS
источник
Подзапрос полностью отличается от соединения, если левая боковая таблица огромна, подзапрос означает, что каждая строка должна выполнять запрос самостоятельно. это станет очень медленным. Присоединиться очень быстро в sql.
yww325
8

До 3.2.6 Mongodb не поддерживает запрос соединения, как и MySQL. ниже решение, которое работает для вас.

 db.getCollection('comments').aggregate([
        {$match : {pid : 444}},
        {$lookup: {from: "users",localField: "uid",foreignField: "uid",as: "userData"}},
   ])
Аниш Агарвал
источник
4

Вы можете запускать SQL-запросы, включая соединение с MongoDB, с помощью mongo_fdw из Postgres.

metdos
источник
3

MongoDB не разрешает объединения, но вы можете использовать плагины для этого. Проверьте плагин Mongo-Join. Это лучшее, и я уже использовал его. Вы можете установить его, используя npm, вот так npm install mongo-join. Вы можете проверить полную документацию с примерами .

(++) действительно полезный инструмент, когда нам нужно объединить (N) коллекции

(-) мы можем применять условия только на верхнем уровне запроса

пример

var Join = require('mongo-join').Join, mongodb = require('mongodb'), Db = mongodb.Db, Server = mongodb.Server;
db.open(function (err, Database) {
    Database.collection('Appoint', function (err, Appoints) {

        /* we can put conditions just on the top level */
        Appoints.find({_id_Doctor: id_doctor ,full_date :{ $gte: start_date },
            full_date :{ $lte: end_date }}, function (err, cursor) {
            var join = new Join(Database).on({
                field: '_id_Doctor', // <- field in Appoints document
                to: '_id',         // <- field in User doc. treated as ObjectID automatically.
                from: 'User'  // <- collection name for User doc
            }).on({
                field: '_id_Patient', // <- field in Appoints doc
                to: '_id',         // <- field in User doc. treated as ObjectID automatically.
                from: 'User'  // <- collection name for User doc
            })
            join.toArray(cursor, function (err, joinedDocs) {

                /* do what ever you want here */
                /* you can fetch the table and apply your own conditions */
                .....
                .....
                .....


                resp.status(200);
                resp.json({
                    "status": 200,
                    "message": "success",
                    "Appoints_Range": joinedDocs,


                });
                return resp;


            });

    });
Amine_Dev
источник
2

Вы можете сделать это с помощью конвейера агрегации, но написать это самостоятельно - боль.

Вы можете использовать mongo-join-queryдля автоматического создания конвейера агрегации из вашего запроса.

Вот как будет выглядеть ваш запрос:

const mongoose = require("mongoose");
const joinQuery = require("mongo-join-query");

joinQuery(
    mongoose.models.Comment,
    {
        find: { pid:444 },
        populate: ["uid"]
    },
    (err, res) => (err ? console.log("Error:", err) : console.log("Success:", res.results))
);

Ваш результат будет иметь пользовательский объект в uidполе, и вы можете связать столько уровней, сколько захотите. Вы можете заполнить ссылку на пользователя, которая ссылается на команду, которая ссылается на что-то еще и т. Д.

Отказ от ответственности : я написал, mongo-join-queryчтобы решить эту проблему.

Марсело Лазарони
источник
0

PlayORM может сделать это для вас, используя S-SQL (Scalable SQL), который просто добавляет разбиение, так что вы можете делать соединения внутри разделов.

Дин Хиллер
источник
-2

Нет, не похоже, что ты делаешь это неправильно. Присоединения MongoDB являются "клиентской стороной". Совсем как ты сказал:

В данный момент я сначала получаю комментарии, которые соответствуют моим критериям, затем вычисляю все uid в этом наборе результатов, получаю пользовательские объекты и объединяю их с результатами комментария. Похоже, я делаю это неправильно.

1) Select from the collection you're interested in.
2) From that collection pull out ID's you need
3) Select from other collections
4) Decorate your original results.

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

На этой странице много чепухи и FUD. Оказывается, 5 лет спустя MongoDB все еще вещь.

Майкл Коул
источник
«вам не нужно иметь дело с дублирующимися строками для« многих »двусторонних объединений» - понятия не имеете, что вы подразумеваете под этим. Вы можете уточнить?
Марк Амери
1
@MarkAmery, конечно. В SQL отношение nn будет возвращать повторяющиеся строки. Например, друзья. Если Боб дружит с Мэри и Джейн, вы получите 2 строки для Боба: Боб, Мэри и Боб, Джейн. 2 Бобса - ложь, есть только один Боб. С клиентскими объединениями вы можете начать с Боба и украсить, как вам нравится: Боб, «Мэри и Джейн». SQL позволяет вам делать это с подзапросами, но это делает работу на сервере БД, которую можно выполнить на клиенте.
Майкл Коул
-3

Я думаю, если вам нужны нормализованные таблицы данных - вам нужно попробовать другие решения для баз данных.

Но я основал это решение для MOngo в Git. Кстати, в коде вставок - у него есть название фильма, но идентификатор noi фильма .

проблема

У вас есть коллекция актеров с массивом фильмов, которые они сняли.

Вы хотите создать коллекцию фильмов с массивом актеров в каждом.

Некоторые образцы данных

 db.actors.insert( { actor: "Richard Gere", movies: ['Pretty Woman', 'Runaway Bride', 'Chicago'] });
 db.actors.insert( { actor: "Julia Roberts", movies: ['Pretty Woman', 'Runaway Bride', 'Erin Brockovich'] });

Решение

Нам нужно пройтись по каждому фильму в документе Actor и создать каждый фильм отдельно.

Улов здесь находится в стадии снижения. Мы не можем создать массив из фазы сокращения, поэтому мы должны построить массив Actors внутри возвращаемого документа «value».

Код
map = function() {
  for(var i in this.movies){
    key = { movie: this.movies[i] };
    value = { actors: [ this.actor ] };
    emit(key, value);
  }
}

reduce = function(key, values) {
  actor_list = { actors: [] };
  for(var i in values) {
    actor_list.actors = values[i].actors.concat(actor_list.actors);
  }
  return actor_list;
}

Обратите внимание, что actor_list на самом деле является объектом javascript, который содержит массив. Также обратите внимание, что карта испускает ту же структуру.

Запустите следующую команду, чтобы выполнить map / lower, вывести ее в коллекцию «pivot» и распечатать результат:

printjson (db.actors.mapReduce (map, lower, "pivot")); db.pivot.find () Foreach (printjson).

Вот пример выходных данных, обратите внимание, что в «Красотке» и «Сбежавшей невесте» есть и «Ричард Гир», и «Джулия Робертс».

{ "_id" : { "movie" : "Chicago" }, "value" : { "actors" : [ "Richard Gere" ] } }
{ "_id" : { "movie" : "Erin Brockovich" }, "value" : { "actors" : [ "Julia Roberts" ] } }
{ "_id" : { "movie" : "Pretty Woman" }, "value" : { "actors" : [ "Richard Gere", "Julia Roberts" ] } }
{ "_id" : { "movie" : "Runaway Bride" }, "value" : { "actors" : [ "Richard Gere", "Julia Roberts" ] } }

Макс Щербаков
источник
Обратите внимание, что большая часть содержания этого ответа (то есть бит на понятном английском языке) скопирована из кулинарной книги MongoDB на ссылке GitHub, предоставленной ответчиком.
Марк Амери
-4

Мы можем объединить две коллекции, используя подзапрос mongoDB. Вот пример, комментарии-

`db.commentss.insert([
  { uid:12345, pid:444, comment:"blah" },
  { uid:12345, pid:888, comment:"asdf" },
  { uid:99999, pid:444, comment:"qwer" }])`

Userss--

db.userss.insert([
  { uid:12345, name:"john" },
  { uid:99999, name:"mia"  }])

Подзапрос MongoDB для JOIN--

`db.commentss.find().forEach(
    function (newComments) {
        newComments.userss = db.userss.find( { "uid": newComments.uid } ).toArray();
        db.newCommentUsers.insert(newComments);
    }
);`

Получить результат из вновь созданной коллекции--

db.newCommentUsers.find().pretty()

Результат--

`{
    "_id" : ObjectId("5511236e29709afa03f226ef"),
    "uid" : 12345,
    "pid" : 444,
    "comment" : "blah",
    "userss" : [
        {
            "_id" : ObjectId("5511238129709afa03f226f2"),
            "uid" : 12345,
            "name" : "john"
        }
    ]
}
{
    "_id" : ObjectId("5511236e29709afa03f226f0"),
    "uid" : 12345,
    "pid" : 888,
    "comment" : "asdf",
    "userss" : [
        {
            "_id" : ObjectId("5511238129709afa03f226f2"),
            "uid" : 12345,
            "name" : "john"
        }
    ]
}
{
    "_id" : ObjectId("5511236e29709afa03f226f1"),
    "uid" : 99999,
    "pid" : 444,
    "comment" : "qwer",
    "userss" : [
        {
            "_id" : ObjectId("5511238129709afa03f226f3"),
            "uid" : 99999,
            "name" : "mia"
        }
    ]
}`

Надеюсь, это поможет.

Кришна
источник
7
Почему вы в основном скопировали этот почти идентичный одногодичный ответ? stackoverflow.com/a/22739813/4186945
хакель