I thought I had gotten quite comfortable with mongodb until I ran in to the following issue. I have a collection of documents in the following format:
{
"_id" : ObjectId("4f876104d976649cbb1f6cf2"),
"course_list" : [
{
"course_id" : "AL101",
"Grade" : "A"
},
{
"course_id" : "PS101",
"Grade" : "B"
},
{
"course_id" : "EL101",
"Grade" : "B"
}
],
"user_name" : "jim"
}
I want to delete all sub-documents from the array "course_list" where "Grade" is NOT EQUAL to "A".
I tried a bunch of different queries, but nothing worked. But then, I thought the following would work for sure, but it didnt either:
db.courses.update({'user_name' : 'jim'}, {$pull : {'course_list' : {'Grade' : {$ne : 'A'}}}})
I get the following array when I run the above command:
Cannot apply $pull/$pullAll modifier to non-array
Can anyone point me in the right direction, please?
Thanks for your comment. My query was indeed correct. The error, as you rightly pointed out, was because of a document where course_list wasn't an array.
Related
I have a mongo db with following structure
{
"_id" : ObjectId("5f59c289fb28ab4476d4578b"),
"data" : [
{
"time" : "10-Sep-2020 11:33:22",
"type" : "Med01",
"id":123
"expdate" : "01-Sep-2021",
"in_stock" "Y"
},
{
"time" : "10-Sep-2020 11:33:22",
"type" : "Med06",
"id":125
"expdate" : "10-Sep-2020",
"in_stock" "N"
},
{
"time" : "10-Sep-2020 11:33:22",
"type" : "LOC1",
"id":103
"expdate" : "10-Sep-2023",
"in_stock" "Y"
}
]
}
I would like to update the in_stock field based on the given id, say for example I need to modify the in_stock of medicine with id 103 to N
I tried with below and it is working but I won't be knowing the list number (2) in advance.
update_one({"_id": id_1}, {'$set': {"data.2.in_stock":'N'}})
I have the value 2 in a variable but not sure how to pass that in the above query. Can someone help?
You need to use the $ positional operator. Note this will match on the first matching array element only.
db.mycollection.update_one({'_id': id_1, 'data.id': 103}, {'$set': {"data.$.in_stock":'N'}})
I have to delete the second comment using index value.. Following is my document structure
{
"_id" : ObjectId("000000000fea5f24282e715b"),
"file_name" : "resume_of_ganga_.docx",
"created_date" : ISODate("2017-11-28T10:29:10.373Z"),
"updated_date" : ISODate("2017-11-28T12:39:32.148Z"),
"comments" : [
{
"created_date" : ISODate("2017-11-28T13:23:51.472Z"),
"status" : "N",
"comment_text" : "Yes...",
"username" : "name"
},
{
"created_date" : ISODate("2017-11-28T13:24:15.938Z"),
"status" : "N",
"comment_text" : "asdsd",
"username" : "name"
}
]
}
I have using this following mongoose query..But my comments are not get deleting
mongo.filemanager.findOneAndUpdate({ "_id": req.body.id},{$pull : {"'comments.' +req.body.c_index" : 1 }},function(err,response){
console.log("Deleted")
});
For example am getting index value as 2.. It should delete the second comment...
Thanks in Advance
I tried looking up to see if MongoDB has any such functionality but seems like they don't from what I found.
A workaround could be something like this. Not sure if this can be considered an atomic operation.
const removeCommentAtIndex = (index) => {
mongo.filemanager.findById(req.body.id, (err, file) => {
file.comments.splice(index, 1);
file.save();
})
}
I executed the accepted answer for In mongoDb, how do you remove an array element by its index in my test database and IT WORKS
mongo.filemanager.findOneAndUpdate({}, {"$unset" : {"comments.1" : 1 }})
mongo.filemanager.findOneAndUpdate({}, {"$pull" : {"comments" : null}})
Note that your req.body.c_index needs to be 1 to remove 2nd comment.
I have a collection data which has around 300k entries and its document looks like
{
"_id" : ObjectId("5xxx85"),
"user_id" : "1",
"name" : "test",
"user_private" : "0"
}
now i want to update all the documents in this collection and new document will look like
{
"_id" : ObjectId("5xxx85"),
"rid" : "1",
"user_name" : "test",
"is_private" : "private",
"is_moderator" : "true",
"amount" : "11111"
}
i.e i need to add new fields, update field names and check if user_private = 0 then put is_private as private or else put is_private as not_private.
I am a bit new so I am not able to get how can i do this efficiently as entries are around 300k.
Please suggest some ways, pseudo code will be really helpful
To update a document a filter criteria. Check pseudo code below and follow link to read more.
You'll need to have an existing value for user_private
db.messages.updateMany([
{ "user_private" : 0 }, // filter.
{ $set: {
"user_private" : "private",
"is_moderator" : "true"
}
}, // update.
{
upsert: true
}
]);
upserts - Creates a new document if no documents match the filter or Updates documents that match the filter based on the filter and update parameters provided.
So I have this document within the course collection
{
"_id" : ObjectId("53580ff62e868947708073a9"),
"startDate" : ISODate("2014-04-23T19:08:32.401Z"),
"scoreId" : ObjectId("531f28fd495c533e5eaeb00b"),
"rewardId" : null,
"type" : "certificationCourse",
"description" : "This is a description",
"name" : "testingAutoSteps1",
"authorId" : ObjectId("532a121e518cf5402d5dc276"),
"steps" : [
{
"name" : "This is a step",
"description" : "This is a description",
"action" : "submitCategory",
"value" : "532368bc2ab8b9182716f339",
"statusId" : ObjectId("5357e26be86f746b68482c8a"),
"_id" : ObjectId("53580ff62e868947708073ac"),
"required" : true,
"quantity" : 1,
"userId" : [
ObjectId("53554b56e3a1e1dc17db903f")
]
},...
And I want to do is create a query that returns all courses that have a specific userId in the userId array that is in the steps array for a specific userId. I've tried using $elemMatch like so
Course.find({
"steps": {
"$elemMatch": {
"userId": {
"$elemMatch": "53554b56e3a1e1dc17db903f"
}
}
}
},
But It seems to be returning a empty document.
I think this will work for you, you have the syntax off a bit plus you need to use ObjectId():
db.Course.find({ steps : { $elemMatch: { userId:ObjectId("53554b56e3a1e1dc17db903f")} } })
The $elemMatch usage is not necessary unless you actually have compound sub-documents in that nested array element. And also is not necessary unless the value being referenced could possibly duplicate in another compound document.
Since this is an ObjectId we are talking about, then it's going to be unique, at least within this array. So just use the "dot-notation" form:
Course.find({
"steps.userId": ObjectId("53554b56e3a1e1dc17db903f")
},
Go back and look at the $elemMatch documentation. In this case, the direct "dot-notation" form is all you need
I have a structure like this:
{
"_id" : ObjectId("501abaa341021dc3a1d0c70c"),
"name" : "prova",
"idDj" : "1",
"list" : [
{
"id" : 1,
"votes" : 2
},
{
"id" : 2,
"votes" : 4
}
]
}
And I'm trying to increase votes with this query:
session_collection.update(
{'_id':session_collection.db.bson_serializer.ObjectID.createFromHexString(idSession),'list.id':idSong},
{$inc:{'list.$.votes':1}},
{safe: true} ,
callback);
But it doesn't work, there are no problems it just doesn't update anything.
I think it's because the ['] (simple quotation mark) on the 'list.id' and 'list.$.votes' because the same query inside the terminal works perfectly.
Thanks!
I suspect your matching is not working as you expect. The callback will return
function(err, numberofItemsUpdated, wholeUpdateObject)
numberofItemsUpdated should equal 1 if your matching worked. you'll need to check if idSession and idSong are what you think they are.