Mongo DB - How to create a dynamic field based on the presence of element in array? - mongodb

I have a problem in Mongo for which I am not getting any clue to resolve it efficiently.
Say I have a 'Course' collection something like this (index is created on the 'studentIds' field):
{
"courseId": 1,
"name": "Mathematics",
"studentIds": [1,3,5]
...
...
}
{
"courseId": 2,
"name": "Physics",
"studentIds": [2,3,5]
...
...
}
I am trying to write a query which would return records in the below format:
Say student 1 is querying the courses, he is enrolled for courseId 1, so the 'enrolled' is true, but student 1 not enrolled for courseId 2 and so the 'enrolled' is false:
{
"courseId": 1,
"name": "Mathematics",
"enrolled": true
}
{
"courseId": 2,
"name": "Physics",
"enrolled": false
}
Only solution I can think of is have two queries, first query to find all course IDs the student is enrolled in and while running through the cursor on the courses in the second query, add 'enrolled' field based on the existence of the courseId in the result of the first query, but looking for a way to achieve this in a single query.
Thanks.

You just need $in operator:
let studentId = 1;
db.collection.aggregate([
{
$project: {
courseId: 1,
name: 1,
enrolled: { $in: [ studentId, "$studentIds" ] }
}
}
])
Mongo Playground

Related

Can't remove object in array using Mongoose

This has been extensively covered here, but none of the solutions seems to be working for me. I'm attempting to remove an object from an array using that object's id. Currently, my Schema is:
const scheduleSchema = new Schema({
//unrelated
_id: ObjectId
shifts: [
{
_id: Types.ObjectId,
name: String,
shift_start: Date,
shift_end: Date,
},
],
});
I've tried almost every variation of something like this:
.findOneAndUpdate(
{ _id: req.params.id },
{
$pull: {
shifts: { _id: new Types.ObjectId(req.params.id) },
},
}
);
Database:
Database Format
Within these variations, the usual response I've gotten has been either an empty array or null.
I was able slightly find a way around this and accomplish the deletion by utilizing the main _id of the Schema (instead of the nested one:
.findOneAndUpdate(
{ _id: <main _id> },
{ $pull: { shifts: { _id: new Types.ObjectId(<nested _id>) } } },
{ new: true }
);
But I was hoping to figure out a way to do this by just using the nested _id. Any suggestions?
The problem you are having currently is you are using the same _id.
Using mongo, update method allows three objects: query, update and options.
query object is the object into collection which will be updated.
update is the action to do into the object (add, change value...).
options different options to add.
Then, assuming you have this collection:
[
{
"_id": 1,
"shifts": [
{
"_id": 2
},
{
"_id": 3
}
]
}
]
If you try to look for a document which _id is 2, obviously response will be empty (example).
Then, if none document has been found, none document will be updated.
What happens if we look for a document using shifts._id:2?
This tells mongo "search a document where shifts field has an object with _id equals to 2". This query works ok (example) but be careful, this returns the WHOLE document, not only the array which match the _id.
This not return:
[
{
"_id": 1,
"shifts": [
{
"_id": 2
}
]
}
]
Using this query mongo returns the ENTIRE document where exists a field called shifts that contains an object with an _id with value 2. This also include the whole array.
So, with tat, you know why find object works. Now adding this to an update query you can create the query:
This one to remove all shifts._id which are equal to 2.
db.collection.update({
"shifts._id": 2
},
{
$pull: {
shifts: {
_id: 2
}
}
})
Example
Or this one to remove shifts._id if parent _id is equal to 1
db.collection.update({
"_id": 1
},
{
$pull: {
shifts: {
_id: 2
}
}
})
Example

MongoDB - Query to fetch all related documents with same relation

Let's say I have a student document that looks something like that:
{
"_id": 1,
"full_name": "John doe",
"gpa": 87,
"class_id": 17
}
My input is one student_id and i need to fetch all of the students from the same class.
I can of course first fetch the student by it's id and then fetch all of the related students by the class_id, but that would take 2 queries.
The question is, can I do it using only one query that returns me an array of all the class students (including the student with the student_id I have as an input)?
First you can group by class_id, so all students are divided into class. Then match the student_id to get all students of that class.
db.collection.aggregate([
{
$group: {
_id: "$class_id",
students: {
$push: "$$ROOT"
}
}
},
{
$match: {
"students._id": 1
}
}
])
Working Mongo playground

How to show specific column in mongo db collection

I tried to show particular columns in mongodb colletion.but its not working.how to show particular columnns.
user_collection
[{
"user_name":"hari",
"user_password":"123456"
}]
find_query
db.use_collection.find({},{projection:{user_name:1}})
I got output
[{
"user_name":"hari",
"user_password":"123456"
}]
Excepted output
[{
"user_name":"hari",
}]
Try:
db.use_collection.find({}, {user_name:1, _id: 0 })
In that way you get the field user_name and exclude the _id.
Extra info:
project fields and project fields excluding the id
With aggregate:
db.use_collection.aggregate( [ { $project : { _id: 0, user_name : 1 } } ] )
You can try this
Mongo query:
db.users.aggregate([
{
"$project":
{
"_id": 0,
"first_name": 1,
}
}
])
Or in ruby (Mongoid)
User.collection.aggregate(
[
"$project":
{
"_id": 0,
"first_name": 1,
}
]
)
If you try to inspect the record, you can convert it into an array first (e.g. User.collection.aggregate(...).to_a)
You can use the official mongodb reference when writing in Mongoid, usually you just need to use double quote on the property name on the left hand side, to make it work on Mongoid.
Try:
db.use_collection.find({}, {user_password:0, _id: 0 ,user_name:1 })

Mongodb Aggregate function with reference to another collection

I have two collections
Persons
{
"name": "Tom",
"car_id": "55b73e3e8ead0e220d8b45f3"
}
...
Cars
{
"model": "BMW",
"car_id": "55b73e3e8ead0e220d8b45f3"
}
...
How can i do a query such that i can get the following results (for example)
BMW : 2
Toyota: 3
Below is my aggregate function. I can get it the data out, however it does the car _id instead of the model name.
db.persons.aggregate([
{
$group: {
_id: {
car_Id: "$car_id",
},
carsCount: {$sum: 1}
},
},
]);
Appreciate any assistance.
you can aggregate internally in one collection with one query. I would suggest to keep aggregated data like that or similar:
{
car_id: 273645jhg2f52345hj3564jh6
sum: 4
}
And replace ID with name when you will need to expose data to the user.

MongoDB: find elements by value of specific element of subarray

I have collection with following document structure:
{
_id: 1,
statuses: [
{
id:3, r:true, date:2016-02-01
},
{
id:2, r:false, date:2015-02-02
},
{
id:3, r:false, date:2015-02-03
}
]
}
How to find all elements from collection where r=false in LAST status where id=3.
If I could sort statuses by date descending, filter it by id=3 and take the first element... Maybe there is smarter way :)