MongoDB - Clearing items in a nested array - mongodb

If I have a nested array in my schema, how do I tell MongoDB to remove its entries for a specific model?
Schema
var UserSchema = new Schema({
username: String,
documents: [Number]
});
I tried something like this:
db.users.update({"username": "tom"}, {"$pullAll": {"documents": []}})
But the items in the nested array are still there.

Your code is not working, because $pullAll requires list of items which should be removed from array. You are passing empty array, thus nothing is removed.
You can simply set documents to empty array instead of removing all items:
db.users.update({"username": "tom"}, {"$set": {"documents": []}})
If you want to avoid creating documents array if "tom" do not have it, then check if array exists when selecting document to update:
db.users.update({username: "tom", documents: {$exists: true}},
{$set: {documents: []}})
UPDATE: Another option to remove all array items is to use $pull with query which satisfies all documents:
db.users.update({username: "tom"}, {$pull: {documents: {$exists: true}}})

Related

MongoDB: update nested value in a collection based on existing field value

I want to update nested _ids over an entire collection IF they are of a type string.
If I have object that look like this...
user : {
_id: ObjectId('234wer234wer234wer'),
occupation: 'Reader',
books_read: [
{
title: "Best book ever",
_id: "123qwe234wer345ert456rty"
},
{
title: "Worst book ever",
_id: "223qwe234wer345ert456rty"
},
{
title: "A Tail of Two Cities",
_id: ObjectId("323qwe234wer345ert456rty")
}
]
}
and I want to change the type of the _Ids from string to ObjectId
how would I do that.??
I have done "this" in the past...But this is working on NON-nested item - I need to change a nested value
db.getCollection('users')
.find({
$or: [
{occupation:{$exists:false}},
{occupation:{$eq:null}}
]
})
.forEach(function (record) {
record.occupation = 'Reader';
db.users.save(record);
});
Any help - I am trying to avoid writing a series of loop on the app server to make db calls - so I am hoping for something directly in 'mongo'
There isn't a way of doing (non $rename) updates operations on a document while referencing existing fields -- MongoDB: Updating documents using data from the same document
So, you'll need to write a script (similar to the one you posted with find & each) to recreate those documents with the correct _id type. To find the subdocuments to update you can use the $type operator. A query like db.coll.find({nestedField._id: {$type: 'string' }}) should find all the full documents that have bad subdocuments, or you could do an aggregation query with $match & $unwind to only get the subdocuments
db.coll.aggregate([
{ $match: {'nestedField._id': {$type: 'string' }}}, // limiting to documents that have any bad subdocuments
{ $unwind: '$nestedField'}, // creating a separate document in the pipeline for each entry in the array
{ $match: {'nestedField._id': {$type: 'string' }}}, // limiting to only the subdocuments that have bad fields
{ $project: { nestedId: 'nestedField._id' }} // output will be: {_id: documentedId, nestedId }
])
I am trying to avoid writing a series of loop on the app server to make db calls - so I am hoping for something directly in 'mongo'
You can run js code directly on the mongo to avoid making api calls, but I don't think there's any way to avoid looping over the documents.

removing element of an array that with a match of certain element

I have a mongodb collection.
{ user_id: 1,
items : [ { _id: 1 }, { _id: 2}, {_id:3} ] }
I want to remove the items of the array having specific id. Can anybody explain what is wrong with the above query.
db.col.findOneAndUpdate({user_id:1},{$pull:{items:{$elemMatch:{_id:2}}}})
$pull takes an expression as a parameter so you don't have to use $elemMatch (doesn't work in this case). Try:
db.col.update({user_id:1},{$pull:{items:{_id:2}}})
So expression in this case means that MongoDB will remove the document having _id set to 2 but that document can have other properties as well.

Meteor + Mongo (2.6.7) Pushing Document to Array in Sorted Order

I have a document with an array (which should be denormalised, but can't be because the reactive events will fire "add" too many times at client startup).
I need to be able to push a document to that array, and keep it in sorted (or roughly sorted) order. I've tried this query:
{ $push: {
'events': {
$each: [{'id': new Mongo.ObjectID, 'start':startDate,...}],
$sort: {'start': 1},
$slice: -1
}
}
But it requires the $slice operator to be present... I don't want to delete all my old data, I just want to be able to insert data into an array, and then have that array be sorted so that I can query the array later and say "slice greater than or equal to time X".
Is this possible?
Edit:
This mongo aggregate query nearly works, except for one level of document in the result array, but aggregating is not reactive (probably because they're expensive computations). Here is the aggregate query if anyone can see how to translate it to a find, or why it can't be translated:
Coll.aggregate({$unwind: '$events'},
{$sort: {'events.start':1}},
{$match: {'events.start': {$gte: new Date()}}},
{$group: {_id: '$_id', 'events': {$push: '$events'} }})

MongoDB: multiple $in on the same field

I want to query mongoDB field for data that is '$in' two lists (arrays) kinda:
{user: {$in: [<array1>]} AND user: {$in: [<array2>]}}
so the query returns only those 'users' that present in both arrays.
I feel this isn't right:
{user: {$in: [<array1>], [<array2>]}}
Any ideas?
Either you can use the $AND operator.
http://docs.mongodb.org/manual/reference/operator/query/and/
{'$AND':[ {'user':{$in: [<..array1..>]} },{'user':{$in: [<..array2..>] } }] }

Removing all embedded documents

I want to remove all embedded documents from a collection, but I can't figure out how to do that.
I have tried a few ways, but I think this one should work:
Products.update({_id: data._id}, { $pull : { orders : {$gte: 0} } });
Products is the collection, orders is the array with embedded documents.
Remove all orders where the index is greater or equal than 0.
No luck.
Try this
db.products.update({_id: data._id},
{$unset: {orders: 1}})
or this
db.products.update({_id: data._id},
{$set: {orders: []}})