2016-02-18 2 views
0

У меня есть две коллекции, которые связаны друг с другом. Палубы и факты.Изучение MongoDB, как найти данные из 2 коллекций

палуб выглядит следующим образом:

{ 
    _id: ObjectId("123456789123456789"), 
    title: "test deck" 
    isActive: true 
} 

Факт выглядит следующим образом

{ 
    _id: ObjectId("111111324324434"), 
    deckId: ObjectId("123456789123456789") 
    title: "test fact" 
} 

я родом из фона SQL, поэтому я хочу, чтобы SELECT * FROM facts LEFT JOIN decks ON decks._id = facts.deckId WHERE deck.isActive = true

Единственный способ я мог понять это был через микро-скрипт.

var deckIds = db.decks.find({isActive: false}, {_id: true}).toArray().map(function(item) { 
return item._id; 
}); 
db.facts.find({deckId: {$in: deckIds}}); 

Это лучший способ сделать это? Есть ли более эффективный способ сделать это все в Монго? Я посмотрел на сокращение карты, но я не могу понять, как это сделать, и это похоже на дополнительный код. В конце я хочу удалить факты, которые имеют deck.isActive = false.

+4

Возможный дубликат [Как выполнить эквивалент SQL Join в MongoDB?] (Http://stackoverflow.com/questions/2350495/how-do-i-perform-the-sql-join-equivalent-in- mongodb) – joao

+0

Мой вопрос: «Это лучший способ». У меня нет mongo 3.2, поэтому я не могу использовать $ lookup. Итак, микро-сценарий выше, лучший? –

+1

Если вы не используете mongo 3.2, у вас не так много вариантов. Вы либо разрабатываете схему данных, так что вам не нужно выполнять объединения, или вы делаете это на стороне клиента (например, сценарий, который вы опубликовали). – joao

ответ

1

MongoDB - это база данных NoSQL, поэтому вы не получите функциональность JOIN. Вы должны делать это вручную, как вы это делаете.

Однако, одна важная вещь, которую следует учитывать, - это моделирование данных. Модели NoSQL имеют тенденцию быть денормализованными, вопреки тому, что считается лучшей практикой в ​​реляционных базах данных, что позволяет нормализовать как можно больше.

Так, может быть, ваш факт документ может включать в себя другие поля деки, для запросов сакэ упрощения в. Я не говорю, что это лучший вариант для вас, но только предупреждаю вас, что в нереляционных базах данных вы должны думать о другом, когда речь идет о моделировании данных. Конечно, каждая модель, которую вы выбираете, влияет на запись и чтение, она в значительной степени зависит от вашей рабочей нагрузки. Это требует некоторых упражнений и практики, но есть некоторые рекомендации, которыми вы можете следовать. Посмотрите на official documentation.

Там хорошая книга из Packt Publishing тоже по этой теме, называется MongoDB Data Modeling.

Хорошо, MongoDB очень эффективен, когда дело доходит до функций (у вас могут быть вложенные документы, массивы, операции на месте и т. Д.), Поэтому у вас есть много вариантов для достижения того, что вам нужно.

Кроме того, не забудьте создать indexes в соответствии с вашими запросами и обновлениями (поле _id автоматически индексируется, а остальное нет).

+0

Да, я согласен, мне часто приходится делать CRUD на фактах и ​​палубах отдельно, поэтому имеет смысл держать их в отдельности. Я просто не был уверен, можно ли использовать функции уменьшения карты или совокупности. –

+0

Карта Уменьшение имеет смысл только тогда, когда у вас есть осколки, когда есть какая-то агрегация, которую вы хотите запустить в фоновом режиме, распространяясь через разные серверы. Его результат будет помещен в другую коллекцию. Кажется, это не то, что вам нужно. Честно говоря, я не очень хорошо разбираюсь в структуре агрегации Mongo, но, насколько я понял, это относится только к одной коллекции, поэтому вы возвращаетесь к той же проблеме: отношения между коллекциями. –

1

Хотя это мышление «SQL», Монго поддерживает этот вид работы с $ lookup (https://docs.mongodb.org/manual/reference/operator/aggregation/lookup/), добавленным в Mongo 3.2. Я построил ваши данные, но использовал строчные буквы для имен; следующие работали, чтобы дать быстрое соединение.

db.facts.aggregate([{$lookup: {from: "decks", localField: "deckId", foreignField: "_id", as: "deck_data"}}]);

дает

{ "_id" : ObjectId("56c5eb065b2de3fa9f8a9d0c"), "title" : "test fact", "deckId" : ObjectId("56c5eadb5b2de3fa9f8a9d0b"), "deck_data" : [ { "_id" : ObjectId("56c5eadb5b2de3fa9f8a9d0b"), "title" : "test deck", "isActive" : true } ] }

Вы можете использовать другие шаги агрегации, просто добавив их объекты в массив. Я рекомендую $ match (эквивалент Find()) и $ project (позволяет выбирать поля).

+0

, если цель состоит в том, чтобы удалить факты на основе поля на deckId, как бы вы использовали агрегирование для выполнения этого удаления? Вы бы использовали это, чтобы получить массив идентификаторов, а затем сделать второе удаление с помощью $ in? –

+0

Я не пробовал это, но похоже, что вы можете создать коллекцию, которую вы хотите, на этапах $ match и $ project, а затем записать ее обратно в ту же коллекцию, используя $ out. Ссылка здесь: https://docs.mongodb.org/manual/reference/operator/aggregation/out/ –

Смежные вопросы