MongoDB: how to define the response object using $match and $project - mongodb

I'm pretty new to MongoDB and I'm trying to query the database and get an object like this in response.
{
activity: 'Aerial Yoga',
participants_12: 10,
participants_13_15: 10,
participants_16_18: 10,
participants_19: 10,
}
I will place an image instead of the full json so I can explain how to get the data:
I can filter but I still don't know how to format the object the DB returns to me. I'm using this query so far:
db.applications.aggregate([
{ $match : {application_number:'SL-O2-2017-05-15-000230', 'sport_activity_list.value.0.properties.sport_activity.value':'Aerial Yoga'}},
{ $project : { _id: 0, "sport_activity_list.value":1,} }
])
How can I achieve the result I want? Should I be using $project? I'm using v3.2.8 of the mongodb

Yes, $aggregate will do this for you. In the $project step you can specify that existing fields should be included or not included with truthy values, but you can also included computed fields, of which this is a very simple example:
db.applications.aggregate([
{ $match : {application_number:'SL-O2-2017-05-15-000230', 'sport_activity_list.value.0.properties.sport_activity.value':'Aerial Yoga'}},
{ $project : {
_id: 0,
value: '$sport_activity_list.value.0.properties.sport_activity.value',
participants_12: '$sport_activity_list.value.0.properties.participants_12.value',
...
} }
])
Hope that helps.

Related

MongoDB : Match with element in an array

I am working on a collection called Publications. Each publication has an array of objectives which are ids. I have also a custom array of objectives hand written. Now, I want to select all the publications that contains at least one element of the custom objectives array in their objectives. How can I do that ?
I've been trying to make this works with '$setIntersection' then '$count' and verify that the count is greater than 0 but I don't know how to implement this.
Example :
publication_1: {
'_id': ObjectId("sdfsdf46543")
'objectives': [ObjectId("1654351456341"), ObjectId("123456789")]
}
publication_2: {
'_id': ObjectId("sdfs216546543")
'objectives': [ObjectId("1654351456341"), ObjectId("46531132")]
}
custom_array = [ObjectId("123456789"), ObjectId("2416315463")]
The mongo query should return publication_1.
You can do like the following:
db.publications.find({
"objectives": {
"$in": [
ObjectId("123456789"),
ObjectId("2416315463")
]
}
})
Notice: "123456789" is not a valid ObjectId so the query itself may not work. Here is the working example
Mongodb playground link: https://mongoplayground.net/p/MbZK99Pd5YR
objectives is an array of objects, I guess you can just query that field directly:
let custom_array = [ObjectId("123456789"), ObjectId("2416315463")];
// You can search the array with $in property.
let result = await Model.find({ objectives: {$in : custom_array} })

How can I traverse a nested document in MongoDB and return the sub-tree?

I have a document with the following structure in MongoDB:
{
"k1": {
"k11": {<extended-sub-document-11>},
"k12": {<extended-sub-document-12>}
},
"k2": {
"k21": {<extended-sub-document-21>}
}
}
How can I fetch the entire object at k12? The find mechanism requires me to provide a value against which to match. But here, I simply want to traverse the path k1/k12 and retrieve the entire sub-document at that key.
Thanks in advance.
Using projection in .find() you can try as like below :
db.collection.find({}, { "k1.k12": 1})
Test : mongoplayground
Note : You would only get values/object of k12 but as it's nested in k1, In the output you would see same structure with just k12 object in k1 like : {k1: {k12: {...}}}.
Using aggregation's $project stage :
db.collection.aggregate([ { $project: {_id :0, k12: "$k1.k12" } } ])
Test : mongoplayground
By using aggregation $project which is way more powerful than projection in .find() you can assign a field's value to a field. In the above query we're assigning value at k1.k12 to a field k12 using $ (Which helps to get value of referenced field).

MongoDB- Query Embedded Document, but Projection Showing Path to key/value?

So basically I want
db.scoreFacts.find(
{"instrumentRanges.flute.minPitch": {$gte: 0, $lte:56}},
{"instrumentRanges.flute.minPitch": 1})
to return
{ "_id" : "Bach_Brandenburg5_Mov1.xml", "minPitch" : 50 }
but instead I get:
{ "_id" : "Bach_Brandenburg5_Mov1.xml", "instrumentRanges" : { "flute" : { "minPitch" : 50 } } }
Essentially the path to "minPitch" is returned, which is not what I need. How can I achieve my desired output with only .find() (no map, etc)? Thanks.
You can't do this with a standard .find() query. If you wish to alter the document structure, look into using an aggregate() call. You can then use projection to define the resulting field(s) you desire.
For example:
db.scoreFacts.aggregate([
{ $match: {"instrumentRanges.flute.minPitch": {$gte: 0, $lte:56}} },
{ $project: {"minPitch": "$instrumentRanges.flute.minPitch"} }
]);
For more information, please see the relevant documentation. Additionally, take a look at the prerequisite aggregation pipeline section.
Note: I have not tested the above query myself, so you may need to alter it somewhat to get the behavior you want.

mongodb how to project first child

I got a mongo db collection with structure
randomstring - means the string is actually random its diffrent in each document of the collection.
{
"notrandom":{
"randomstring":{
"randomstring":{
"randomstring":{
"notrandom2":"data"
}
}
}
}
}
how can i project this data out?
something like
db.mydb.aggregate( "notrandom[0][0].notrandom2":1}} , ] )
what i'm trying to achieve is a collection of all the notrandom2 values.
if you you to move notrandom2 to higer level in document structure,
you could use $project stage like this:
{
$project:{
_id:1,
notrandom2:"notrandom.randomstring.randomstring.randomstring.notrandom2",
// list all others fields with field:1 if you want them to appear down in pieline
}}
if this field is a part of an array then you need to $unwind first and then $project
You can use the following query
db.mydb.find({<findquery (in you have any)>},{"notrandom.randomstring.randomstring.randomstring.notrandom2" : 1}).
toArray(function(err, result)
{
console.log(result); //Array of objects with `notrandom2` values
})

MongoDB querying by sub-document value not working as expected

I have two schemas, a Profile and a LevelOfNeed.
Profile
{
"_id" : ObjectId("56d35960a695dfa140137fca"),
. . .
"levelOfNeedServiced" : ObjectId("56d35828a695dfa140137fc7")
}
Level of Need
{
"_id" : ObjectId("56d35828a695dfa140137fc7"),
"sortOrder" : 2,
"description" : "Moderate Needs",
"additionalCost" : 3,
"__v" : 0
}
I currently have 4 documents for LevelOfNeed. What I need to do is select all of the Profile documents where the levelOfNeedServiced.sortOrder is >= a value.
Example:
db.getCollection('profiles').find({
'levelOfNeedServiced.sortOrder': { $gte: 2 }
})
Given my data, I would expect to see the example Profile, but this returns no results. What am I doing wrong?
Update 1
Previously, I was running MongoDB 3.0.9. I've since upgraded to 3.2.3, however I'm still getting the same results. According to the docs, I should be able to query on an embedded document field value.
Update 2
The aggregate function solution works as expected, but since I already had an array of LevelOfNeed objects, I was able to use that to get to the related documents I needed using the $in operator.
Unfortunately mongodb does not support joins until version 3.2. In version 3.2 it provides the $lookup aggregation operator to lookup referenced documents across collections.
You could use it as below:
db.Profile.aggregate([
{
$lookup:{
"from":"LevelOfNeed",
"localField":"levelOfNeedServiced",
"foreignField":"_id",
"as":"joined"
}
},
{
$match:{
"joined.sortOrder":{$gte:2}
}
},
{
$project:{"levelOfNeedServiced":1,...} //include things you want to project.
}
])
Your code:
db.getCollection('profiles').find({
'levelOfNeedServiced.sortOrder': { $gte: 2 }
})
does not work as intended because, the field levelOfNeedServiced is identified as a field containing an ObjectId and not the resolved LevelOfNeed document.