Updating multiple MongoDB records in Sails.js - mongodb

I need to update multiple records in mongodb.
From frontend logic , i got the array of id's as below.
ids: [ [ '530ac94c9ff87b5215a0d6e6', '530ac89a7345edc214618b25' ] ]
I have an array of ids as above , i need to update the folder field for all the records in that array.
I tried passing the id's to mongodb query as below , but still that doesn't work.
Post.native(function(err, collection) {
collection.update({
_id : {
"$in" : ids
}
}, { folder : 'X'}, {
multi : true
}, function(err, result) {
console.log(result);
});
});
Please help.

There seem to be two possible problems.
1) your ids array is not an array of ids, it's an array which has a single element which is itself an array, which has two elements. An array of ids would be `[ 'idvalue1', 'idvalue2']
2) your id values inside of arrays are strings - is that how you are storing your "_id" values? If they are ObjectId() type then they are not a string but a type ObjectId("stringhere") which is not the same type and won't be equal to "stringhere".

There is no reason to use the native method in this case. Just do:
Post.update({id : ids}, {folder : 'X'}).exec(console.log);
Waterline automatically does an "in" query when you set a criteria property to an array, and Sails-Mongo automatically translates "id" to "_id" and handles ObjectId translation for you.

Those strings look like the string representation of mongod ObjectIds, so probably what you want to do is turn them into ObjectIds before querying. Assuming you've corrected your problem with the extra level of nesting in the array, that is:
ids = ['530ac94c9ff87b5215a0d6e6', '530ac89a7345edc214618b25']
Then you want to do something like this:
oids = []
for (var i in ids)
oids.push(ObjectId(ids[i]))
db.c.find({_id: {$in: oids}})
Does that fix your problem?

Related

MongoDB new ObjectId over array giving me same Id for all

I am trying to update items in an array with unique ObjectIds (meaning add an object ID to array object that are missing them)
If I have an array of shirt objects in my collection and I try this:
db.people.update({
$and : [
_id: ObjectId('5eeb44c6a042791d28a8641f'),
{
$or: [
{ 'shirts._id': { $eq:null } },
{ 'shirts._id':{ $exists:false } }
]
}
]
},{
$set: { 'shirts.$[]._id': new ObjectId() }
},{
"multi" : true
}
);
It generates IDENTICAL ObjectsIDs for each array element, I would put an unique index on this however, the use case probably wont see more then 2-3 items in the array with edge cases hitting 5-6, which seems like an abuse of an index
How can I update multiple records or multiple array objects with a unique ObjectId?
When you use $set you're telling mongo to set that value to all matching elements. If the elements in the array are already defined as schemas, mongo will issue new ObjectIds for each one of them automatically.
Alternatively, you can use forEach and iterate over each matching element creating a new ObjectId.

Return MongoDB documents that don't contain specific inner array items

How can I return a set of documents, each not containing a specific item in an inner array?
My data scheme is:
Posts:
{
"_id" : ObjectId("57f91ec96241783dac1e16fe"),
"votedBy" : [
{
"userId" : "101",
"vote": 1
},
{
"userId" : "202",
"vote": 2
}
],
"__v" : NumberInt(0)
}
I want to return a set of posts, non of which contain a given userId in any of the votedBy array items.
The official documentation implies that this is possible:
MongoDB documentation: Field with no specific array index
Though it returns an empty set (for the more simple case of finding a document with a specific array item).
It seems like I have to know the index for a correct set of results, like:
votedBy.0.userId.
This Question is the closest I found, with this solution (Applied on my scheme):
db.collection.find({"votedBy": { $not: {$elemMatch: {userId: 101 } } } })
It works fine if the only inner document in the array matches the one I wish not to return, but in the example case I specified above, the document returns, because it finds the userId=202 inner document.
Just to clarify: I want to return all the documents, that NONE of their votedBy array items have the given userId.
I also tried a simpler array, containing only the userId's as an array of Strings, but still, each of them receives an Id and the search process is just the same.
Another solution I tried is using a different collection for uservotes, and applying a lookup to perform a SQL-similar join, but it seems like there is an easier way.
I am using mongoose (node.js).
User $ne on the embedded userId:
db.collection.find({'votedBy.userId': {$ne: '101'}})
It will filter all the documents with at least one element of userId = "101"

Mongo $addToSet still inserting despite item in array existing

I am trying to insert a new array item into an array of objects using $addToSet as I don't want duplicates
var location = {
place : req.body.location.Place,
postcode : req.body.location.Postcode
}
User.update({_id: req.body._id},
{$addToSet: { 'locations' : location}}, function(err, data) {
});
This inserts a record every time even if place and postcode exactly match.
Thanks
I think that your results are not the same (they might look the same, but have invisible characters). For example:
db.a.insert({_id : 1, locs: []});
And then no matter how many times do you addToSet objects to the array locs:
db.a.update({_id : 1},{$addToSet : {
locs: {a : 1, b: 2}
}})
Only the first one will be added.
So take a look at what are you adding, then try to do a raw mongo shell attempt. If it does not work correctly, post it here. Otherwise look more precisely at the data your app is providing to mongo.
Thanks for your help Salvador
It seems as I'm using Mongoose it adds the _id, I needed to create a subDocument or new schema for the array and set the _id to false
locations : [new mongoose.Schema(
{
place : String,
postcode : String
},
{ _id: false})
]
All working fine now

updating Mongoose documents with nested arrays at multiple indexes

I'm having trouble updating a schema with a nested array to have one objectID in multiple rows of the array. Please help if you can!
My Schema looks like this:
var ProblemSchema = new Schema({
data : "etc..."
array1 : [{
_id : { type: 'String' },
array2: [{ type: Schema.Types.ObjectId}]
}]}
I can easily add an objectId to a SINGLE nested array using the $ operator in the update object like so:
var query = {array1._id : ID};
var update = {$push : {'array1.$.array2' : objectId}};
Problem.update(query, update)
I want to be able to, however, add the same objectId to MULTIPLE array2s (i.e. corresponding to different array1 ids) in one query, but the $ operator only matches to the first match to the query so I can't do it the way outlined above.
I'm also trying to avoid having a for loop on the server (I realize I could find() the correct document then use a for loop in which I manually push() the objectID to the correct array2s but the solution involves large overhead), can anyone think of a solution?
As of MongoDB 2.6, there's no way to do this with with a single update query. The $ positional operator is a placeholder for the first matching element in an array. There's a MongoDB feature request for updating all matching elements of an array, SERVER-1243, that you can track in the meantime.

using an Object (subdocument) with varying fields as _id

Our (edX) original Mongo persistence representation uses a bson dictionary (aka object or subdocument) as the _id value (see, mongo/base.py). This id is missing a field.
Can some documents' _id values have more subfields than others without totally screwing up indexing?
What's the best way to handle existing documents without the additional field? Remove and replace them? Try to query w/ new _id format and if fails fall over to query w/o the new field? Try to query with both new and old _id format in one query?
To be more specific, the current format is
{'_id': {
'tag': 'i4x', // yeah, it's always this fixed value
'org': your_school_x,
'course': a_catalog_number,
'category': the_xblock_type,
'name': uniquifier_within_course
}}
I need to add 'run': the_session_or_term_for_course_run or 'course_id': org/course/run.
Documents within a collection need not have values for _id that are of the same structure. Hence, it is perfectly acceptable to have the following documents within a collection:
> db.foo.find()
{ "_id" : { "a" : 1 } }
{ "_id" : { "a" : 1, "b" : 2 } }
{ "_id" : { "c" : 1, "b" : 2 } }
Note that because the index is on only _id, only queries that specify a value for _id will use the index:
db.foo.find({_id:1}) // will use the index on _id
db.foo.find({_id:{state:"Alaska"}) // will use the index on _id
db.foo.find({"_id.a":1}) // will NOT use the index on _id
Note also that only a complete match of the "value" of _id will return a document. So this returns no documents for the collection above:
db.foo.find({_id:{c:1}})
Hence, for your case, you are welcome to add fields to the object that is the value for the _id key. And it does not matter that all documents have a different structure. But if you are hoping to query the collection by_id and have it be efficient, you are going to need to add indexes for all relevant sub parts that might be used in isolation. That is not super efficient.
_id is no different than any other key in this regard.