mongoose nodeJs, группа по внешнему ключу, где ID находится в массиве [duplicate]

Chrome Исправлены проблемы безопасности на версии 36.0.1985.125

Chrome 36.0.1985.125 СРЕДА, 16 ИЮЛЯ 2014 Примечание к выпуску

Из моего наблюдения, это обновление устранило проблему при использовании window.close(), чтобы закрыть всплывающее окно. Вы увидите это на консоли, когда оно не получится: «Скрипты могут закрывать только открытые им окна». Это означает, что хакерские обходные пути (ответ Брок Адамса) могут не работать в последней версии.

Таким образом, в предыдущих выпусках, выпущенных Chrome, приведенный ниже блок кода может работать, но не с этим обновлением.

window.open('', '_self', '');
window.close();

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

chrome.windows.remove(integer windowId, function callback)

для его удаления. API расширений Chrome API можно найти на странице chrome.windows .

На самом деле мое расширение chrome MarkView столкнулось с этой проблемой, и мне пришлось обновить свой код, чтобы он работал для этого обновления Chrome. Кстати, MarkView - это инструмент для чтения и записи Awesome Markdown Files, он предоставляет функции, включая Content Outline, Sortable Tables и подсветку синтаксиса блока кода с номером строки.

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

406
задан Ozair Kafray 19 June 2012 в 12:55
поделиться

19 ответов

Что касается Монго 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.

232
ответ дан Ahmad Baktash Hayeri 19 August 2018 в 00:18
поделиться
  • 1
    это $ lookup performance-wise лучший вариант? – Mohsen Shakiba 21 November 2015 в 10:06
  • 2
    Согласовано. Это лучший ответ . – NDB 23 November 2015 в 14:21
  • 3
    @clayton: Как насчет более двух коллекций? – Dipen Dedania 8 January 2016 в 11:36
  • 4
    @DipenDedania просто добавляет дополнительные $ lookup этапы в конвейер агрегации. – Clayton Gulick 9 January 2016 в 02:01
  • 5
    Я не могу присоединиться к любому полю в массиве в левой коллекции с его соответствующим идентификатором в правой коллекции. Кто-нибудь может мне помочь? – Prateek Singh 1 February 2016 в 17:52

Вы можете присоединиться к двум коллекциям в Монго, используя поиск, который предлагается в версии 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.

7
ответ дан Alex M 19 August 2018 в 00:18
поделиться

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

 db.getCollection('comments').aggregate([
        {$match : {pid : 444}},
        {$lookup: {from: "users",localField: "uid",foreignField: "uid",as: "userData"}},
   ])
5
ответ дан Anish Agarwal 19 August 2018 в 00:18
поделиться

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

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

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 сколько угодно таблиц.

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

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

Python code ..

db.LeftTable.aggregate([
                        # connect all tables

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

                        ])

Шаг 2: Определите все условные выражения

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

Python Code ..

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: undefine all conditionals

Python Code ..

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
                        }}

                        ])

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

7
ответ дан Community 19 August 2018 в 00:18
поделиться
0
ответ дан Dean Hiller 19 August 2018 в 00:18
поделиться

$ lookup (aggregation)

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

Equality Match

Чтобы выполнить совпадение равенства между полем из входных документов с полем из документов «объединенной» коллекции, этап $ 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> );

Mongo URL

2
ответ дан GoutamS 19 August 2018 в 00:18
поделиться

Вот пример коллекции "join" * Актеры и фильмы:

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

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

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

17
ответ дан JosephSlote 19 August 2018 в 00:18
поделиться
  • 1
    -1, Это НЕ присоединяется к данным из двух коллекций. Он использует данные из одной коллекции (участников), вращающейся вокруг. Итак, теперь все, что было ключом, теперь значения и значения теперь являются ключами ... very , отличными от JOIN. – Evan Teran 22 May 2012 в 18:44
  • 2
    – Thomas Decaux 17 June 2012 в 20:16
  • 3
    Но лучший подход. Очень полезно спасибо – Singh 15 October 2015 в 13:45

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

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

Пользователи -

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"
        }
    ]
}`

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

-4
ответ дан Krishna 19 August 2018 в 00:18
поделиться

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

http://docs.mongodb.org/ecosystem/tutorial/model-data- for-ruby-on-rails /

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

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

130
ответ дан KyleMit 19 August 2018 в 00:18
поделиться
  • 1
    Тогда почему так много людей любят MongoDB. Я не понимаю: | – Boris D. Teoharov 15 September 2013 в 16:47
  • 2
    @dudelgrincen - это переход парадигмы от нормализации и реляционных баз данных. Цель NoSQL - очень быстро читать и писать из базы данных. С BigData у вас будет множество приложений и серверов с более низким числом в DB. Вы должны делать миллионы транзакций в секунду. Выгрузите тяжелую работу из базы данных и поместите ее на уровень приложения. Если вам нужен глубокий анализ, вы запускаете задачу интеграции, которая помещает ваши данные в базу данных OLAP. В любом случае вы не должны получать много глубоких запросов от OLTP-dbs. – Snowburnt 4 November 2013 в 03:53
  • 3
    @dudelgrincen Я должен также сказать, что это не для каждого проекта или дизайна. Если у вас есть что-то, что работает в базе данных типа SQL, зачем это менять? Если вы не можете массировать свою схему для работы с noSQL, тогда не делайте этого. – Snowburnt 12 November 2013 в 02:30
  • 4
    Миграции и постоянно меняющиеся схемы также намного проще управлять в системе NoSQL. – justin 6 May 2014 в 21:09
  • 5
    Что делать, если пользователь имеет 3.540 сообщений на веб-сайте, и он меняет свое имя пользователя в профиле? Следует ли обновлять каждое сообщение с новым именем пользователя? – Ivo Pereira 2 March 2016 в 18:39

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

Вы можете использовать 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
ответ дан Marcelo Lazaroni 19 August 2018 в 00:18
поделиться
-2
ответ дан Max Sherbakov 19 August 2018 в 00:18
поделиться

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

3
ответ дан metdos 19 August 2018 в 00:18
поделиться

Нет, похоже, что вы делаете это неправильно. Соединения 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 все еще есть.

-3
ответ дан Michael Cole 19 August 2018 в 00:18
поделиться
  • 1
    'вам не нужно иметь дело с повторяющимися строками для "many & quot; односторонние объединения - не знаю, что вы подразумеваете под этим. Вы можете уточнить? – Mark Amery 20 September 2015 в 20:23
  • 2
    Вниз, правда? – Michael Cole 21 September 2015 в 14:46
  • 3
    @MarkAmery, конечно. В SQL отношение n-n возвращает повторяющиеся строки. Например. Друзья. Если Боб дружит с Мэри и Джейн, вы получите 2 строки для Боба: Боб, Мэри и Боб, Джейн. 2 Бобс - ложь, есть только один Боб. При подключении на стороне клиента вы можете начать с Боба и украсить, как вам нравится: Боб, «Мэри и Джейн». SQL позволяет вам делать это с помощью подзапросов, но это работает на сервере db, который может быть выполнен на клиенте. – Michael Cole 21 September 2015 в 14:51
2
ответ дан Michael Mior 19 August 2018 в 00:18
поделиться

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

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

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

9
ответ дан NDB 19 August 2018 в 00:18
поделиться

Мы можем объединить / объединить все данные внутри одной коллекции с простой функцией в нескольких строках с помощью клиентской консоли 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" : [ ]
}

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

127
ответ дан Orlando Becerra 19 August 2018 в 00:18
поделиться
  • 1
  • 2
    Что происходит, когда один из объектов-ссылок получает обновление? Это обновление автоматически отражается в объекте книги? Или этот цикл необходимо запустить снова? – balupton 4 June 2014 в 06:55
  • 3
    Это нормально, пока ваши данные малы. Он будет доводить содержимое каждой книги до вашего клиента, а затем забирать каждую категорию, кредитование и авторов один за другим. Когда ваши книги будут тысячами, это будет действительно очень медленным. Лучшим методом, вероятно, будет использование конвейера агрегации и вывод объединенных данных в отдельный сборник. Позвольте мне снова вернуться к нему. Я добавлю ответ. – Sandeep Giri 19 June 2014 в 16:31
  • 4
    Можете ли вы адаптировать свой алгоритм к этому другому примеру? stackoverflow.com/q/32718079/287948 – Peter Krauss 22 September 2015 в 14:13
  • 5
    @SandeepGiri, как я могу выполнить агрегатный конвейер, так как у меня действительно действительно интенсивные данные в разделенной коллекции нужно объединить? – Yassine Abdul-Rahman 7 October 2015 в 20:16

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

34
ответ дан Otto Allmendinger 19 August 2018 в 00:18
поделиться
  • 1
    Кажется, неправильная производительность, исходящая из фона сервера sql, но, может быть, это не так плохо с документом db? – terjetyl 15 July 2010 в 19:20
  • 2
    от фона сервера sql, я был бы признателен MongoDB, взяв «набор результатов» (с выбранными возвращенными полями) в качестве входных данных для нового запроса за один раз, подобно вложенным запросам в SQL – Stijn Sanders 27 November 2010 в 00:17
  • 3
    @terjetyl Вы должны действительно планировать это. Какие поля вы собираетесь представлять на лицевой стороне, если это ограниченная сумма в отдельном представлении, вы берете их как встроенные документы. Ключ не должен делать соединения. Если вы хотите сделать глубокий анализ, вы делаете это после факта в другой базе данных. Запустите задание, которое преобразует данные в куб OLAP для обеспечения оптимальной производительности. – Snowburnt 4 November 2013 в 03:56
  • 4
    От версии mongo версии 3.2 поддерживаются левые соединения. – Somnath Muluk 26 November 2015 в 12:12
10
ответ дан Snowburnt 19 August 2018 в 00: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
    }
});
16
ответ дан VishAl 19 August 2018 в 00:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: