Query a Many-to-Many relation in MongoDB - mongodb

I am reading MongoDB in Action and when talking about querying many-to-many relationships in a Document, I'm having difficulty understanding how he wrote his example query (using the Ruby driver).
The query is finding all products in a specific category, where there is a products and category collection. The author says "To query for all products in the Gardening Tool category, the code is simple:
db.products.find({category_ids => category['id']})
A PRODUCT doc is like this:
doc =
{ _id: new ObjectId("4c4b1476238d3b4dd5003981"),
slug: "wheel-barrow-9092",
sku: "9092",
name: "Extra Large Wheel Barrow",
description: "Heavy duty wheel barrow...",
details: {
weight: 47,
weight_units: "lbs",
model_num: 4039283402,
manufacturer: "Acme",
color: "Green"
},
category_ids: [new ObjectId("6a5b1476238d3b4dd5000048"),
new ObjectId("6a5b1476238d3b4dd5000049")],
main_cat_id: new ObjectId("6a5b1476238d3b4dd5000048"),
tags: ["tools", "gardening", "soil"],
}
And a CATEGORY doc is like this:
doc =
{ _id: new ObjectId("6a5b1476238d3b4dd5000048"),
slug: "gardening-tools",
ancestors: [{ name: "Home",
_id: new ObjectId("8b87fb1476238d3b4dd500003"),
slug: "home"
},
{ name: "Outdoors",
_id: new ObjectId("9a9fb1476238d3b4dd5000001"),
slug: "outdoors"
}
],
parent_id: new ObjectId("9a9fb1476238d3b4dd5000001"),
name: "Gardening Tools",
description: "Gardening gadgets galore!",
}
Can someone please explain it a little more to me? I still can't understand how he wrote that query :(
Thanks all.

The query is searching the products collection for all products with a value of category['id'] in the field category_ids
When you search a field that contains an array for a specific value, MongoDB automatically enumerates each value in that array searching for matches.
To construct the query, you must first notice that the category collection defines your category hierarchy, and that each category has a unique ID (stored, as is usual in MongoDB, in the _id field)
You must also notice that the product collection has a field that stores a list of category ids, category_ids, that reference the unique ids of the category collection.
Therefore, to find all products in a particular category, you search the category_ids field of the product collection for the unique ID of the category you're interested in, which you get from the category collection.
If I were to write a query for the Mongo javascript based shell interpreter, mongothat find products in the Gardening Tools category, I would do the following:
Look up the ID of the Gardening Tools category (which, as noted before, is stored in the _id field of the category collection)
In this case, the value in your example is ObjectId("6a5b1476238d3b4dd5000048")
Insert the value into a query that searches through the category_ids field of the product collection
This is the query that you give in your question, which for the mongo shell I would write as: db.products.find({category_ids : new ObjectId("6a5b1476238d3b4dd5000048")})
I hope that's clearer than the original explanation!
(As an aside: I'm not quite sure what language your query is written in, is it perhaps PHP? In any case, javascript seems to be the language of choice for examples in the MongoDB docs because the MongoDB server installs the mongo command line interpreter alongside the server itself, so everyone has access to it)

Related

Relationship of a model with an array of Ids of other model in Lucid Mongo

Right now, I have a mongoldb database of a classroom and make an API using AdonisJS & Lucid Mongo. In the classroom there's a collection called students and another called classes. The structure of both collections are the following.
students = {
_id: ObjectID
name: string
age: number
}
classes = {
_id: ObjectID
name: string
professorId: ObjectID
students: ObjectID[]
}
As you can see, in classes collection I have an array with students. How can I call this relationship using Lucid Mongo or just simple mongodb
Unfortunately, Lucid Mongo doesn't support yer aggregate pipeline but I solve this using referMany method in Classes model as follow:
students() {
return this.referMany('App/Models/Student','_id','studentsId)
}
well if you are early in your schema design you should flatten out of a related table design into a single collection where class is a doc in the student collection:
students = {
_id: ObjectID
name: string
age: number
class = {
_id: ObjectID
name: string
professorId: ObjectID
}}
In the related schema that you have now; one must use an aggregate pipeline on the class collection and $unwind the Class - Student array into individual student docs by student and then $lookup the Student collection.
well if the original question is how to 'call the relationship' and you have those 2 collections - the method is to use $lookup on the related field (name).
where you go from there depends on the specifics of what data/fields you wish to display in your final query results.
that a student is in multiple classes doesn't change the $lookup need. It will impact how your final query is designed and that depends on the specific results you seek i.e. single student, all students, class count, class names, etc...
if you are early in your schema design and can change from related to flat - as per my first post - this is more efficient in an NoSQL approach. for instance a simple $match on a student would make the display of their classes very simple. It can also be done in the related collections you now have but it is a little more involved.

Caching search results in MongoDB

I have a DB with a user collection, a book collection, and a comment collection.
I would like to perform a site-wide search capability and for that reason I would like to create a new collection of indexed content for search entries.
The new collection I imagine will look like this:
var indexContent= mongoose.Schema({
keyword:String //The keyword search
rank: Number //a ranking I give the matched document
refType: String //either "User", "Series", or "Episode"
ref: mongoose.Schema.Types.ObjectId //The id of the matched document,
date: Date // date when this entry was created
})
I feel like this is ideal because, whenever a keyword exists in the collection I can quickly retrieve the results, and if the keyword was never searched before, I generate the results for the first time, then save it to serve to other people.
The problem is, considering the site has a very high rate of updates, how often should I dump my cached results?

One to Many Relationship mongoDB

I have a quick question regarding one to many relationships in mongoDB. I have mainly used SQL before this so im getting confused about how to approach relationships. I have viewed all the documentation online and it does not give a good example of how to set up and query a one to many relationship.
Say I have a table of Users and each user has many products. This means that in an SQL situation multiple products in the table would have the same user foreign_key. In mongoDB I have tried to replicate this by placing each users object id into the corresponding product that they are selling much like a foreign key.
Im getting confused on how I would query it. For example how would I do SELECT * FROM USERS, PRODUCTS WHERE USER_ID = USERFK_ID;?
Ive read about document references, embedded document but its just confusing me more. Does anyone have a straight explanation please.
Assuming I understood your question, I will have a users collection and a products collection.
The users collection will contain users and their details. E.g.
{id: '007', name: 'john'}
{id: '010', name: 'paul'}
The products collection will contain products linked to given users. E.g.
{id: '432738', name: 'apple', price: '100', owner: '007'} i.e. owner is john
As pertaining the query, I will do something like this:
db.collection('products').find({owner: user_id_here})
A one-to-many relationship is where the parent document can have many child documents, but the child documents can only have one parent document.
db.artists.insert(
{
_id : 3,
artistname : "Moby",
albums : [
{
album : "Play",
year : 1999,
genre : "Electronica"
},
{
album : "Long Ambients 1: Calm. Sleep.",
year : 2016,
genre : "Ambient"
}
]
}
)

MongoDB docs, one-to-many example, why are the references different?

The MongoDB docs show an example of a one to many relationship...
(Abbreviated...)
Model One-to-Many Relationships with Document References
// Publisher.
{
_id: "oreilly",
name: "O'Reilly Media",
}
// Book.
{
_id: 123456789,
title: "MongoDB: The Definitive Guide",
publisher_id: "oreilly"
}
// Book.
{
_id: 234567890,
title: "50 Tips and Tricks for MongoDB Developer",
publisher_id: "oreilly"
}
Why is the publisher _id a logical, human-readable name while the book _ids appear to be generated surrogate keys?
Wouldn't all _ids be generated values?
Is it conventional in MongoDB to sometimes use the data itself as a unique key and sometimes not?
If so, when do we use ordinary names ("mary", "joe", "exxon"), and when do we prefer generated values?
Wouldn't all _ids be generated values?
MongoDB auto-generates _id only when it is not provided by the user.
Is it conventional in MongoDB to sometimes use the data itself as a
unique key and sometimes not?
Yes, The data can be used as the key. The _id value has to be unique in a collection to correctly identify a document. Any parameter in the document can be set as the _id if it satisfies the above criteria. When the _id is not unique in a collection the duplicate key error is thrown.
If so, when do we use ordinary names ("mary", "joe", "exxon"), and
when do we prefer generated values?
We prefer a generated _id when there is no parameter(or parameter groups), that uniquely identify the document. For example, using the name of a person will not work because, there might come a situation to add another person with the same name. However, consider a books ISBN number, it uniquely identifies a book. Such parameters can be used as _id.
Additional Notes:
The auto-generated _id has embedded timestamp value (which may be of use).
No need to worry about duplicate values with auto-generated _id.
However, an user specified _id value may be more application/domain specific.

How to make the "join" of an array of objects ids with MongoDB

I'm facing some dificult to make this query with the MongoDB Aggregation Framrwork.
I have a order collection that has an array of objects ids from products example:
{
_id: "5759b760aeacbfa420943d84",
products: [
"57718a2c9473f30ae88d1875",
"57727d988d7e581809b454a1",
"577bda7da756e2180507a944"
]
}
Here is an example of one document from my products ocllection:
{
_id: "57718a2c9473f30ae88d1875",
name: "Soap A"
}
How can I make an aggregation query in orders to get a list of contained products documents?
The short answer you can't.
Aggregate works only on one collection.
However if you are using mongoose you can use query and '.populate' method
i.e
CollectionModel.find({}).populate('products').exec(function(err, items) {})
more details on populate http://mongoosejs.com/docs/populate.html
but that only applicable to nodejs application however language you are using have a look at some ORM frameworks for mongo
I hope that helps