Reputation: 1456
I've got 2 collections that are related. Decks and Facts.
Decks looks like this:
{
_id: ObjectId("123456789123456789"),
title: "test deck"
isActive: true
}
A fact looks like this
{
_id: ObjectId("111111324324434"),
deckId: ObjectId("123456789123456789")
title: "test fact"
}
I come from a SQL background so I want to SELECT * FROM facts LEFT JOIN decks ON decks._id = facts.deckId WHERE deck.isActive = true
The only way I could figure this out was via a micro script.
var deckIds = db.decks.find({isActive: false}, {_id: true}).toArray().map(function(item) {
return item._id;
});
db.facts.find({deckId: {$in: deckIds}});
Is this the best way to do this? Is there a more performant way to do this all in Mongo? I looked at map-reduce but I can't figure out how to do this there and it seemed like way more code. What I want to do in the end is delete the facts that have deck.isActive = false.
Upvotes: 0
Views: 64
Reputation: 392
While that is the "SQL" way of thinking, Mongo does support this kind of work with $lookup (https://docs.mongodb.org/manual/reference/operator/aggregation/lookup/) added in Mongo 3.2. I built your data out, but used lower case for names; the following worked to yield a quick join.
db.facts.aggregate([{$lookup: {from: "decks", localField: "deckId", foreignField: "_id", as: "deck_data"}}]);
yields
{ "_id" : ObjectId("56c5eb065b2de3fa9f8a9d0c"), "title" : "test fact", "deckId" : ObjectId("56c5eadb5b2de3fa9f8a9d0b"), "deck_data" : [ { "_id" : ObjectId("56c5eadb5b2de3fa9f8a9d0b"), "title" : "test deck", "isActive" : true } ] }
You can apply other aggregation steps just by adding their objects to the array. I recommend $match (equivalent of a Find()) and $project (allows selection of fields).
Upvotes: 1
Reputation: 2696
MongoDB is a NoSQL database, so you won't get native JOIN functionality. You are supposed to do that manually, as you are doing.
However, one essential thing to consider is data modeling. NoSQL models tends to be denormalized, contrary to what is considered a best practice in relational databases, which is to normalize as much as you can.
So, maybe, your fact document could include other deck's fields, for querying simplification's sake. I'm not saying this is the best option for you, but only warning you that in non relational databases, you should think different when it comes to data modeling. Off course, every model you choose has impacts on writing and reading, it depends heavily on your workload. This demands some exercising and practice, but there's some guidelines you can follow. Look at the official documentation.
There's a good book from Packt Publishing too about this topic, called MongoDB Data Modeling.
The good thing is, MongoDB is very powerful when it comes to features (you can have nested documents, arrays, in-place operations, etc), so you have many options to achieve what you need.
Also, don't forget to create indexes according to your queries and updates (the _id field is automatically indexed, the rest not).
Upvotes: 1