nested subdocument update in mongodb - node.js

{
"_id": "581dc52e2c26be354164d528",
"name": "vipin",
"__v": 0,
"post": [
{
"like": "today",
"_id": "581dc52e2c26be354164d529",
"comment": [
{
"date": "today",
"username": "vipin",
"_id": "581dc52e2c26be354164d52a",
"detail": [
{
"time": "now",
"day": "saturday",
"_id": "581dc52e2c26be354164d52b"
}
]
}
]
}
]
},
i have a nested subdocument.i want to update comment .date.but i cant do this .i want to nested subdocument update but query is not work.
Test.update({"_id":"581dc52e2c26be354164d528","post._id":"581dc52e2c26be354164d529","comment._id":"581dc52e2c26be354164d52a" },{
"$set":{
"post.$.comment.0.date.0":"tommorow"
}
},function(err,data){
if(data){
res.json(data)
};
if(err){
res.json(err)
}
})
}
my query is now worked .plzz anybody suggest me .

mongodb don't support positional operator matching nested arrays. check this issue it's still in open status:
https://jira.mongodb.org/browse/SERVER-831
workaround : use aggregation and fetch required subdocument make modifications and update subdocument using update query.

Okkk.we can update our nested subdocument in mongodb.this is our schema.
var Post = new mongoose.Schema({
name:String,
post:[{
like:String,
comment:[{
date:String,
username:String,
detail:{
time:String,
day:String
}
}]
}]
})
Now we can update our choosed field in mongoDb.if your document contains more than array of field like post,comment than it can be poor .but we can use many objects.like ......than we have no problem on updating.
post:[{
like:String,
comment:{
date:String,
username:String,
detail:{
time:String,
day:String,
address:{
street:String,
house:String
}
}
}
}]
})
so we have solution of first Schema is like this.our mongoDb query is working properly .so check this...
for first schema.if we have take more than one array in subdocument.
Test.update({"post._id":"58206a6aa7b5b99e32b7eb58"},
{$set:{
"post.$.comment.0.detail.time":"aajtk"}},
for second schema .if we have take more than objects.
db.tests.update({"post._id":ObjectId("58204e89cfee37f023a567bd")},{$set:{"post.$.comment.detail.time":"News"}})

Related

mongoose find in document object

Lets say I have a mongoose schema, something like:
mongoose.Schema({
website_id:mongoose.SchemaTypes.ObjectId,
data:Object
})
where data field contains JSON Object. Something like:
{
"actions":[
{
"action":"pageChange",
"url":"http://localhost:3000/login",
"dom":"",
"timestamp":1653341614846
},
{
"action":"pageChange",
"url":"http://localhost:3000/signup",
"dom":"",
"timestamp":1653341626442
},
{
"action":"pageChange",
"url":"http://localhost:3000/view",
"dom":"",
"timestamp":1653341626442
},
{
"action":"pageChange",
"url":"http://localhost:3000/login",
"dom":"",
"timestamp":1653341626442
}
]
}
Is there any way I can get all documents, where data field object contains http://localhost:3000/login as url, without getting all the documents first and looping them through.
Object is going to be dynamic generated, and items will repeat themselves
Of course, there are several ways and in this case, one of the best ways is to use "aggregate"
db.collection.aggregate([
{$unwind: "$actions"},
{ $match: {"actions.url": "http://localhost:3000/login"}},
{$group: {
_id: "$_id",
actions: {$push: "$actions"}
}
}
])
return Response :
{
"actions": [
{
"action": "pageChange",
"dom": "",
"timestamp": 1.653341614846e+12,
"url": "http://localhost:3000/login"
},
{
"action": "pageChange",
"dom": "",
"timestamp": 1.653341626442e+12,
"url": "http://localhost:3000/login"
}
]
}
If i find other or better methods, I'll definitely share..
I hope this solution helps you.
Sure you can do that. You can specify the object nesting in form of string in the query.
await MyModel.find({ 'data.objectKey.items.item': 'text I want to find' }).exec();

How can I write query in mongodb?

I have a collection of mongodb like this :
[{
"_id":"ObjectId(""51780fb5c9c41825e3e21fc4"")",
"name":"CS 101",
"students":[
{
"name":"raj",
"year":2016
},
{
"name":"rahul",
"year":2017
},
{
"name":"anil",
"year":2018
}
]
},
{
"_id":"ObjectId(""51780fb5c9c41825e3e21fs4"")",
"name":"CS 102",
"students":[
{
"name":"mukesh",
"year":2016
},
{
"name":"mohan",
"year":2017
},
{
"name":"mangal",
"year":2018
}
]
}
]
I've been looking for similar questions like this one: Mongo db - Querying nested array and objects but in that question they're looking for a specific element inside the "messages" object (in my case) for example. Same as in this other question: Query for a field in an object in an array with Mongo? where they're using $mapan d I don't think it fits my needs.
The documents to find have this structure:
[{
"_id":"ObjectId(""51780fb5c9c41825e3e21fc4"")",
"name":"CS 101",
"students":[
"raj","rahul","anil"
]
},
{
"_id":"ObjectId(""51780fb5c9c41825e3e21fs4"")",
"name":"CS 102",
"students":[
"mukesh","mohan","mangal"
]
}
]
how to solve this?
From the question and datasets, you are trying to return students with an array of student's name (string) instead of the array of student object.
Use $project to display students as students.name array.
db.collection.aggregate([
{
$project: {
"_id": "$_id",
"name": "$name",
"students": "$students.name"
}
}
])
Sample Solution 1 on Mongo Playground
OR
Use $set to replace the students field with students.name array.
db.collection.aggregate([
{
$set: {
"students": "$students.name"
}
}
])
Sample Solution 2 on Mongo Playground

Mongodb update all the documents with unique id

I have collection with name products with almost 100k documents. I want to introduce a new key called secondaryKey with unique value uuid in all the documents.
I do this using nodejs.
Problem I am facing:-
When I try the below query,
db.collection('products').updateMany({},{"$set":{secondaryKey: uuid()}});
Here it updates all the documents with same uuid value,
I try with loop to update document one by one,but here issues is I don't have filter value in updateOne because I want to update all the documents.
Can anyone please help me here.
Thanks :)
If you are using MongoDB version >= 4.4 You can try this:
db.products.updateMany(
{},
[
{
$set: {
secondaryKey: {
$function: {
body: function() {
return UUID().toString().split('"')[1];
},
args: [],
lang: "js"
}
}
}
}
]
);
Output
[
{
"_id": ObjectId("..."),
"secondaryKey": "f41b15b7-a0c5-43ed-9d15-69dbafc0ed29"
},
{
"_id": ObjectId("..."),
"secondaryKey": "50ae7248-a92e-4b10-be7d-126b8083ff64"
},
{
"_id": ObjectId("..."),
"secondaryKey": "fa778a1a-371b-422a-b73f-8bcff865ad8e"
}
]
Since it's not the same value you want to put in each document you have to use the loop.
In your loop, you have to update the current document of the iteration. So you have to filter with the _id in the updateOne
The above reply didn't work for me. Plus, it compromises security when you enable javascript on your database (see here $function and javascript enabling on database). The best way is to not overload your server, do your work on local as below:
const { nanoid, customAlphabet } = require('nanoid')
async function asdf() {
const movies = await client.db("localhost").collection("productpost");
var result2 = []
let result = await movies.find({}).toArray()
result.forEach(element => {
const nanoid = customAlphabet('1234567890', 10)
console.log(element.price)
element.price = 4
element.id = nanoid()
result2.push(element)
});
console.log("out reult2", result2)
await movies.deleteMany({})
await movies.insertMany(result2)
})
It will delete any objects on your collections and update with the new ones. Using nanoid as uniqueids.
This is the database object array after adding unique id:
{ "_id": { "$oid": "334a98519a20b05c20574dd1" }, "attach": "[\"http://localhost:8000/be/images/2022/4/bitfinicon.png\"]", "title": "jkn jnjn", "description": "jnjn", "price": 4, "color": "After viewing I am 48.73025772956596% more satisfied with life.", "trademark": "", "category": "[]", "productstate": "Published", "createdat": { "$date": "2022-04-03T17:40:54.743Z" }, "language": "en"}
P.S: Please backup your collection before doing this or filter the array on your needs for not going through all collection.

How to populate updated document by id in schema array

I am trying to learn and implement few operations which are newer for me. I have a child schema details which I am pushing in a parent schema array. Everything is going fine. But when it comes to front-end, concern about few things.
As per someone's advice ,I came to know we must store _id to another schema . And if we update details of that _id, it will get reflected in every schema docs where it has been stored.
Now I am login through parent schema and I want to see the entire details of those array _id as I need to show lists in front-end. Right now I can only see ids. I want to populate array of entire object of those ids.
I can populate data but I need to use a different API Url to show list. I do not want that . I know if I change ObjectId to Mixed, I can see whole object. But problem is that it will not show updated data. So I am pushing by ObjectId users:[ {type: mongoose.Schema.Types.ObjectId, ref: 'Userr'}]
So how will I populated updated users aray data on my main schema array without creating new route api ??
Child schema:-
{
"_id": "5d034653ff1e426fb0e3fca1",
"firstName": "xyz",
"lastName": "fg",
"__v": 0
}
Main schema response details :-
{
"admins": {
"users": [
"5d034653ff1e426fb0e3fca1" //<========= what i am getting
],
"email": "1cf1eede89#himail.online",
"password": "$2a$10$vHyGxX9P.t0/ybKcmIzkc.ZCX18oHaVnvTgJIWA2gTNzJ3TCdXS4a",
},
"_id": "5d0339d5b4b28b6ddff06802",
"companyID": "497399",
"__v": 0
}
I want to show result like this :
{
"admins": {
"users": [
"5d034653ff1e426fb0e3fca1",
"firstName" : "xyz",
"lastName" :"fg"
],
"email": "1cf1eede89#himail.online",
"password": "$2a$10$vHyGxX9P.t0/ybKcmIzkc.ZCX18oHaVnvTgJIWA2gTNzJ3TCdXS4a",
},
"_id": "5d0339d5b4b28b6ddff06802",
"companyID": "497399",
"__v": 0
}
Function for registering user :-
if(req.userData.role2 === 'admin') {
console.log("saving successful");
res.send(doc);
Admin.findOneAndUpdate({ _id: req.userData.userId }, { $push: { 'admins.users': userr._id } }, { new: true })
.populate('admins.users')
.exec(function(error, res){
if (error) {
console.log(error);
}else {
console.log(res.admins.users+ "populated")
}
});
}
This is showing me list of populate data but how can I show it in array object
I need to show the updated object of child schema. So that I can use in front-end for listing whatever details I want

mongodb remove document if array count zero after $pull in a single query

I have a requirement where my comments schema looks like the following
{
"_id": 1,
"comments": [
{ "userId": "123", "comment": "nice" },
{ "userId": "124", "comment": "super"}
]
}
I would like to pull the elements based on the userId field.
I am doing the following query
comments.update({},{$pull:{comments:{userId:"123"}}})
My requirement is that if the array length became zero after the pull operator I need to remove the entire document for some reason.Is there a away to do this in a single query?
PS:I am using the mongodb driver.Not the mongoose
If I'm reading your question right, after the $pull, if the comments array is empty (zero length), then remove the document ({ _id: '', comments: [] }).
This should remove all documents where the comments array exists and is empty:
comments.remove({ comments: { $exists: true, $size: 0 } })
I had a similar requirement and used this (using mongoose though):
await Attributes.update({}, { $pull: { values: { id: { $in: valueIds } } } }, { multi: true })
await Attributes.remove({ values: { $exists: true, $size: 0 } })
Not sure if it's possible to do this in one operation or not.
You can use middlewares for this.
http://mongoosejs.com/docs/middleware.html
Write a pre/post update method in mongodb to check your condition.

Resources