I have a MongoDB collection with documents that follows this shape:
"peopleList": [
{
"_id": "List 1 id",
"name": "List 1",
"people": [
{
"_id": "A Person id",
"name": "A Person",
"email": "person#email.com"
},
{
"_id": "Another Person id",
"name": "Another Person",
"email": "another.person#email.com"
},
],
},
{
"_id": "List 2 id",
"name": "List 2",
"people": [
{
"_id": "A Person id",
"name": "A Person",
"email": "person#email.com"
},
],
}
]
As you can see, the same Person object can appear in multiple lists.
So what I want is to retrieve all lists that a given person is part.
For e.g:
Passing _id: "A Person id" -> the query should return List 1 and List 2,
Passing _id: "Another Person id:" -> the query should return only List 1.
I tried this query:
await PeopleList.find({ people: { _id: 'A person id' } });
But the query returned an empty array, even 'A person id' is a document present in many lists.
EDIT
Sharing the Fahad answer, the correct query is:
await PeopleList.find({
people: { $elemMatch: { _id: mongoose.Types.ObjectId('A person id') }
}});
Lets assume that your mongo schema name is PeopleList so your filter query will be like this
PeopleList.find({people : {$elemMatch:{_id: mongoose.Types.ObjectId('321321321321321')}});
For more info you can see documentation here
You have to use $elemMatch and $in to find in array. So try like this
"people": { $elemMatch: { "_id": { $in: [mongoose.Types.ObjectId(params.id) ] } } }
Related
I want to update my courseModules inside MasterCourse. In below JSON I have two Objects in courseModules. I want if moduleId exist in courseModules then update it else create a new object and return the courseModules with updated value.
I am using Node js and mondodb, mongoose. Not able to find how can I achieve this functionality.
JSON OR MONGODB Data:
"MasterCourse": [
{
"_id": "6392f2611e7d670eca9712fa",
"courseTitle": "My Course Title",
"awardURL": "award.png",
"courseModules": [
{
"moduleId": 0,
"moduleTitle": "Module Title 1",
"moduleDescription": "Module 1 description",
"totalSessions": 3,
"_id": "6392f2611e7d670eca97e12d"
},
{
"moduleId": 1,
"moduleTitle": "ModuleTitle 2",
"moduleDescription": "Module 2 description",
"totalSessions": 4,
"_id": "6392f2611e7d670eca9711wd"
},
],
}
]
Query want to perform:
{
"moduleId": 2,
"moduleTitle": "Module Title 3",
"moduleDescription": "Module 3 description",
"totalSessions": 8,
}
To add if item not exist -
masterCourse.updateOne({ "_id": req.params.id }, { $addToSet: { "courseModules": req.body } })
To update the value if exist -
masterCourse.updateOne({ "_id": req.params.id, "courseModules._id": ModuleID }, { $set: { "courseModules": req.body } })
These queries works for me, you can change the variable's name according to your data or requirement.
I have two collections. One to store all the user Details and another to store movies. I have a user_id field which has the objectId of the user who uploads it in the movie collection.
Now I need to store all the movie ObjectId's as a array in the corresponding user collection. Like one to many relationship.
say,
I have some movie documents :
[{
'id' : '1',
'title' : 'Pk',
'user_id' : '25'
},
{
'id' : '2',
'title' : 'Master',
'user_id' : '25'
}]
In user collection, I want to store all the Movie_id's as a array to the corresponding user.
{
'user_id' : '25',
'user_name' : 'john',
'Movie_ids' : ['1','2']
}
How can I achieve this using mongodb and express.js?
Query
$lookup does what you want (see mongodb documentation is very good)
$map is used to keep only the ids in the array
Test code here
db.users.aggregate([
{
"$lookup": {
"from": "movies",
"localField": "user_id",
"foreignField": "user_id",
"as": "movies"
}
},
{
"$set": {
"movies": {
"$map": {
"input": "$movies",
"in": "$$this.id"
}
}
}
}
])
Ok, I'm not sure if this is entirely what you are looking for but you can use javascript function .filter on the movie object to get all the movies with user_id=25 and then map the id's of those movies to a new array like this:
let movies = [
{
"id": "1",
"name": "pk",
"user_id": "25"
},{
"id": "2",
"name": "Master",
"user_id": "25"
}]
let user = {
"id": "25",
"name": "john"
}
let sortedMovies = movies.filter(movie => movie.user_id === user.id).map(movie => movie.id);
user.movieIDs = sortedMovies;
A link to test the code: https://playcode.io/816962/
I am new to mongodb and im trying to (as title says) "Given an array of matches, find all documents that have atleast one match and replace all matches with given value"
For example, lets say i have those documents in my mongodb:
[
{
"_id": ObjectId("5e90880a39cfeaaf0b97b576"),
"StudentName": [
"Chris, C",
"David, O",
"Mike, K",
"Sam, Bard"
]
},
{
"_id": ObjectId("5e90880a39cfeaaf0b97b577"),
"StudentName": [
"Joe, J",
"John, K",
"David, O",
"Sam, Ba rd",
"Sam, B"
]
}
]
And i want to find all documents that contains either ["Sam, B", "Sam, Bard", "Sam, Ba rd"] and replace with "Sam"
Expected result:
[
{
"_id": ObjectId("5e90880a39cfeaaf0b97b576"),
"StudentName": [
"Chris, C",
"David, O",
"Mike, K",
"Sam"
]
},
{
"_id": ObjectId("5e90880a39cfeaaf0b97b577"),
"StudentName": [
"Joe, J",
"John, K",
"David, O",
"Sam",
"Sam"
]
}
]
What i tried to do:
db.collection.updateMany({ "StudentName": {"$in":["Sam, B", "Sam, Bard", "Sam, Ba rd"]} },{ "$set": { "StudentName.$": "Sam" } })
Which didn't work. Any help? Thank you very much.
EDIT1: I need it to be dynamic, i'll be providing the array of possibles matches and the string to replace with through a NodeJS application.
EDIT2: To give an example for EDIT1, i could pass an array like this ["John,"Bob","Jessica","Robert"] to replace with "Josh"
There are several ways you can do this. By the looks of it you want this to be done via one command that can be run directly in the shell.
You can do this leveraging arrayFilters option within updateMany. See https://docs.mongodb.com/manual/reference/method/db.collection.updateMany/#std-label-updateMany-arrayFilters for further documentation on it.
For simplicity I won't leverage indices so the below command would iterate over all the documents in the collection. If you want to leverage an index you would just adjust the query portion of the updateMany
db.collection.updateMany(
{ },
{ $set: { "StudentName.$[element]" : "Sam" } },
{ arrayFilters: [ { "element": /.*Sam.*/i } ] }
)
The above will replace any value that contains "Sam" with the value "Sam". So "Sam I Am" would be replaced with "Sam".
If you know the values you are trying to replace:
db.students.updateMany(
{ },
{ $set: { "StudentName.$[element]" : "Ana" } },
{ arrayFilters: [ { "element": { $in: ["John", "Jessica", "Robert", "Rob"] } } ] }
)
which would replace all values of John, Jessica, Robert and Rob with "Ana".
I have nested array documents explained below:
countries: [
{
"id": "id of country",
"cities": [
{
"id": "id of city 1",
"areas": [
{
"id": "id of area 1"
},
{
"id": "id of area 2"
},
{
"id": "id of area 3"
},
{
"id": "id of area 4"
}
]
},
{
"id": "id of city 2",
"areas": [
{
"id": "id of area 1"
},
{
"id": "id of area 2"
},
{
"id": "id of area 3"
},
{
"id": "id of area 4"
}
]
}
]
}
]
My target is to add a field using $addFields to indicate if a given id matching area ID or not.
{$addFields: {
isDeliveringToArea: {
$in: [ObjectId('5db5d11cb18a2500129732a5'),'$countries.cities.areas.id']
}
}}
but apparently $in doesn't work with nested arrays.
I want something like the find method works Model.find({'countries.cities.areas.id': 'areaID'}) but to return a boolean value in the aggregation.
Since there are 3 level nested arrays, we can achieve this with $map which is used to run all/modify the objects. First $map used to go through each country object, the second $map used to go each city objects inside each country object
Update 1
Since you need over all filed, you can do it with $anyElementTrue which helps if there is any element true on our condition, it will emit true.
Working Mongo play ground for overall country
[
{
"$addFields": {
isDeliveringToArea: {
$anyElementTrue: {
$map: {
input: "$countries",
in: {
$anyElementTrue: {
$map: {
input: "$$this.cities",
in: {
$in: [
"6",
"$$this.areas.id"
]
}
}
}
}
}
}
}
}
}
]
I keep the old query for your reference.
Working Mongo playground for each country object
I have 2 arrays. users and posts. posts contain a property "post_by" which is the id of one of the users. I need to match the user and push the first & last name into the post object as a new property. Goal is I need to display the name of the user that made the post in a table.
note* I can use javascript, jquery, linq.js or lodash.
fiddle with json
fiddle
var users = [
{
"id": "15e640c1-a481-4997-96a7-be2d7b3fcabb",
"first_name": "Kul",
"last_name": "Srivastva",
},
{
"id": "4cada7f0-b961-422d-8cfe-4e96c1fc11dd",
"first_name": "Rudy",
"last_name": "Sanchez",
},
{
"id": "636f9c2a-9e19-44e2-be88-9dc71d705322",
"first_name": "Todd",
"last_name": "Brothers"
},
{
"id": "79823c6d-de52-4464-aa7e-a15949fb25fb",
"first_name": "Mike",
"last_name": "Piehota"
},
{
"id": "e2ecd88e-c616-499c-8087-f7315c9bf470",
"first_name": "Nick",
"last_name": "Broadhurst"
}
]
var posts = [
{
"id": 1,
"status": "Active",
"post_title": "test title",
"post_body": "test body",
"post_by": "4cada7f0-b961-422d-8cfe-4e96c1fc11dd"
},
{
"id": 2,
"status": "Fixed",
"post_title": "test title two",
"post_body": "test body two",
"post_by": "79823c6d-de52-4464-aa7e-a15949fb25fb"
}
]
https://jsfiddle.net/zy5oe25n/7/
console.log($.map(posts, function(post){
var user = $.grep(users, function(user){
return user.id === post.post_by;
})[0];
post.first_name = user.first_name;
post.last_name = user.last_name;
return post;
}));
Here's a lodash approach:
_.map(posts, function(item) {
return _.assign(
_.pick(_.find(users, { id: item.post_by }),
'first_name', 'last_name'),
item
);
});
It's using map() to map the posts array to a new array of new objects (immutable data). It's then using find() to locate the user object, and uses pick() to get the properties we need. Finally, assign() adds the post properties to the new object that pick() created.
For good measure, using linq.js.
var userMap = Enumerable.From(users).ToObject("$.id");
posts.forEach(function (post) {
var user = userMap[post.post_by];
if (user) {
post.first_name = user.first_name;
post.last_name = user.last_name;
}
});
Note, we're using the builtin forEach() for arrays, linq.js is not needed for that part.