How to search a Mongo collection for a document that contains an array that contains an element that meets a particular criteria? - mongodb

I'm new at Mongo and there might be a better way to do what I want. I'm dealing with a particular data structure that my application must process.
Suppose that I have a collection that contains two documents that contain information about universities and their student clubs to include the name of each club and the name of each student in each club along with their age:
{
_id: 1, // object ID
name: "Oxford University",
clubs: [{
name: "Soccer",
members: [{
name: "Alice",
age: 22
},
{
name: "Bob",
age: 23
}
]
}, {
name: "Gymnastics",
members: [{
name: "Charlie",
age: 20
},
{
name: "Dorothy",
age: 19
}
]
}]
}
{
_id: 2, // object ID
name: "Cambridge University",
clubs: [{
name: "Chess",
members: [{
name: "Ellen",
age: 30
},
{
name: "Frank",
age: 35
}
]
}, {
name: "Go",
members: [{
name: "Gilbert",
age: 25
},
{
name: "Hikari",
age: 40
}
]
}]
}
Suppose that I want to write a query on this collection that will find universities that have a club that has at least one member aged 40 or older.
How do I do that?
I sketched this example based off of the idea of taking some JSON documents and inserting them into a new collection. Maybe it would be a better idea to break this apart into multiple collections. I just had the idea to research if Mongo might be a good product to use in this situation given that a big part of my job here is to create something that can receive some JSON data, process it, and make it queryable.

MongoDB queries have a convenient feature to query documents that have a specific value or condition in embedded objects and arrays. In the query you can specify the "path" to the object or array using "dot notation" without having to specify the exact array index, etc.
Using your example, you can find the documents where a member of a club is aged 40 or older like this.
db.collection.find({
"clubs.members.age": {
"$gte": 40
}
})
This returns the second document in your example collection.
Try it on mongoplayground.net.

Related

Mongoose: Populate path which is not an individual collection

I have two collections, let's call it collection A & B.
Inside collection A, I have an array of Objects with structure like -
Collection A
[{
_id: "<mongo_id>",
department: "gastro",
doctors: [{
_id: "<mongo_id>",
name: "Lorem Ipsum",
type: "Surgeon",
age: 45
},{
_id: "<mongo_id>",
name: "Dolor Sit Amet",
type: "General Physician",
age: 36
}]
}]
Then inside the collection B, I have this array object _id from collection A, as a reference.
let say -
Collection B
[{
_id: "<mongo_id>",
name: "John Doe",
assignedDoc: "<_id_of_doctor_from_collection_A>",
appointmentDate: 2020-08-29T12:09:18.153+00:00
},{
_id: "<mongo_id>",
name: "Jane Doe",
assignedDoc: "<_id_of_doctor_from_collection_A>",
appointmentDate: 2020-08-29T12:09:18.153+00:00
}]
Now I want to populate the _id of assignedDoc in collection B, to show the doc details from collection A.
Anyone knows, how can we do that?
Basically, I don't want to create a separate collection for doctors, as that won't be nosql approach as much I know. That will be kind of sql relatioship approach.
Or If I'm wrong or my approach is not correct, please guide me.
Any kind of help will be greatly appreciated.
Thanks!

Difference between Reference Mapping and Embedded Mapping

What is the difference between Reference Mapping and Embedded Mapping in Doctrine MongoDB ODM?
I just need to implement one to many relationship.
Embedded documents are stored within the document itself. Referenced documents are stored elsewhere.
A simplified example of how Referenced docs are stored in the db:
//collection one
{
_id: "one_1"
many: [
"many_1",
"many_2",
"many_3"
]
}
//collection many
{
_id: "many_1",
name: "one"
},
{
_id: "many_2",
name: "two"
},
{
_id: "many_3",
name: "three"
}
and Embedded documents:
//collection one
{
_id: "one_1"
many: [
{ _id: "many_1", name: "one"},
{ _id: "many_2", name: "two"},
{ _id: "many_3", name: "three"}
]
}
The former is more flexible, the later is way quicker.
The rule of thumb is to go with references if you need to modify sub-documents individually, or if you need many-to-many refs, or if you can reach the 16MB size limit due to huge number of embedded documents in the foreseeable future.

What is the mongodb equivalent of sorting over GROUPed BY field

I have two collections in MongoDB. Let's call one "objects":
{
_id: 11,
name: "Foo"
},
{
_id: 12,
name: "Bar"
},
{
_id: 13,
name: "Quux"
}
Another one is "values", that references "objects":
{
_id: 21,
value: "One",
object_id: 11
},
{
_id: 22,
value: "Two",
object_id: 11
},
{
_id: 21,
value: "Three",
object_id: 13
}
I want to query "objects" collection, showing the number of incoming links from "values" for each document in "objects" and sort by that number, in an descending order. I want to receive something like this:
{
_id: 11,
name: "Foo",
links: 2
},
{
_id: 13,
name: "Quux"
links: 1
},
{
_id: 12,
name: "Bar",
links: 0
}
In SQL, this is achievable using a simple outer join, GROUP BY and ORDER BY.
I can't use MapReduce (this must be an online query, not a scheduled job). I can't denormalize anything as "objects" and "values" in reality are collections of pretty large documents with lots of legacy code depending on their exact structure.
Any advice?
MongoDB has no JOINs. There is no way to get data from more than one collection with a single query. This means you need to program the JOIN on the application layer and then do your GROUP BY, also in the application. How to do this depends on the technology which your application is using.
Sorry, but this is what you get when you structure your data for MongoDB as if it were an SQL database.

Pushing data into nested arrays in MongoDB

Whats the best way of pushing data into an array that's nested several levels deep in arrays...
Here's an example document ( made up ) that's representative of the data in the document, except the real document has more schools with more classes and more students. Each 'thing' has a unique id :-
{
_id: 4353467865,
school : [
{
_id: 3425353,
name: 'school of rock',
class: [
{
_id: 3242342
name: 'Room1',
students: [
{ _id: 345456562, name: 'Kevin' }
]
},
{
// more classes with more students nested underneath
}
]
},
{
// more schools, classes, students...
}
]
}
Now I know the id of the document, school and class, and now I want to do an update $push into the students array a {_id: 234554363, name: 'Barry'} for that class.
How do I construct an update query for that?
Do the below 2 links solve your problem?
http://docs.mongodb.org/manual/reference/operator/update/positional/#nested-arrays
Update multi nested array in Mongodb
I'll answer my own question since I've been using Mongo for a while now.
first answer...
When designing Mongo stuff, I was super paranoid to try and get things in one doc if I could since that's the whole benefit. Reality is you don't have to be too paranoid. School and Class could be separate collections. It does depend a bit on how you are using them, but for the most I would do separate collections these days.
second answer...
I have needed to do nested arrays, however any level of nesting array can be separated out into non nested arrays with keys which is then trivial to update using mongo
so
school : [
{
_id: 3425353,
name: 'school of rock',
}
],
classes: [
{
_id: 3242342
school_id: 3425353,
name: 'Room1',
}
],
students: [
{ _id: 345456562, class_id: 3242342, name: 'Kevin' }
{ _id: 345456563, class_id: 3242342, name: 'Gilbert' }
]

MongoDB - $addToSet on a list of Embedded Document

I have a list of (mongodb) Embedded Documents within one Document and I am interested in adding a new embedded document to the list of the existing ones.
As far as I have researched, I can use $addToSet, what I can't figure out is how does MongoDB decide if the new document already exists in the list of embedded documents or if it's a new one, i.e. how does MongoDB decide if 2 embedded documents are equal?
p.s. the embedded documents I have are not just values, they are quite complex structures, so I was wondering if there is any place I can define what the equality between 2 of them means...
$addToSet uses the usual mongodb equality rules: it will do a deep value-by-value comparison, so the following two documents are identical:
{ name: "John", hobbies: ["coding", "drinking", "chess"] }
{ hobbies: ["coding", "drinking", "chess"], name: "John" }
(order within documents is not guaranteed, so they are identical)
while those aren't (pairwise):
// compare to:
{ name: "John", hobbies: ["chess", "coding", "drinking"] }
// in arrays, the order matters:
{ name: "John", hobbies: ["coding", "drinking", "chess"] }
// field names and values are case sensitive
{ Name: "John", hobbies: ["chess", "coding", "drinking"] }
{ name: "john", hobbies: ["chess", "coding", "drinking"] }
// additional field:
{ name: "John", lastName: "Doe", hobbies: ["chess", "coding", "drinking"] }
// missing field:
{ name: "John" }
Please note that there is no special field here. You can add an _id field, but it has no special semantics and will be treated just like any other field.