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.
Related
I'm using MongoDB inside a twig framework. I'm trying to determine if the user has access to a certain module.
(a part of) my DB entry looks like:
_id: "579b50a4f5092761a20f4e71",
approvedModules: [
"examplemodule",
"examplemodule1",
"examplemodule2",
"examplemodule3"
],
My code looks like:
session.get('__AUTH_USER').find({ approvedModules : { '$in' : ["examplemodule"]}}, { '$exists' : true })
(the standard functions have to be in quotes).
I keeps returning false. I can only return the value if I use session.get('__AUTH_USER').approvedModules.0
I don't want to include the .0 because that might change.
What am I doing wrong?
Thanks in advance!
What am I doing wrong?
Many things. The worst one is using queries to database inside a template, but it is another problem.
You misunderstood purpose of the $in operator, which is used to match a field in the database to any element of array in the query.
To match any element of array in the collection to a single value you can do simple $eq:
session.get('__AUTH_USER').find({ approvedModules : "examplemodule"})
When you are using $in operator, you need to have 2 input arguments, the first one is the value for which you are checking the array, and the second one should be the array itself.
So, your bson element should look like this:
isModuleInArray : { '$in' : ["examplemodule","$approvedModules"] }
I have a mongoDB document that has the following structure:
{
user:user_name,
streams:[
{user:user_a, name:name_a},
{user:user_b, name:name_b},
{user:user_c, name:name_c}
]
}
I want to use $pullAll to remove from the streams array, passing it an array of streams (the size of the array varies from 1 to N):
var streamsA = [{user:"user_a", name:"name_a"},{user:"user_b", name:"name_b"}]
var streamsB = [{name:"name_a", user:"user_a"},{name:"name_b", user:"user_b"}]
I use the following mongoDB command to perform the update operation:
db.streams.update({name:"user_name", {"$pullAll:{streams:streamsA}})
db.streams.update({name:"user_name", {"$pullAll:{streams:streamsB}})
Removing streamsA succeeds, whereas removing streamsB fails. After digging through the mongoDB manuals, I saw that the order of fields in streamsA and streamsB records has to match the order of fields in the database. For streamsB the order does not match, that's why it was not removed.
I can reorder the streams to the database document order prior to performing an update operation, but is there an easier and cleaner way to do this? Is there some flag that can be set to update and/or pullAll to ignore the order?
Thank You,
Gary
The $pullAll operator is really a "special case" that was mostly intended for single "scalar" array elements and not for sub-documents in the way you are using it.
Instead use $pull which will inspect each element and use an $or condition for the document lists:
db.streams.update(
{ "user": "user_name" },
{ "$pull": { "streams": { "$or": streamsB } }}
)
That way it does not matter which order the fields are in or indeed look for an "exact match" as the current $pullAll operation is actually doing.
I have a collection which have a document like this:
collection 1
{
_id: ObjectID(),
name: foo
}
I would get ObjectID of the above collection and copy into a document of another collection in order to reference correctly. Should I do simply:
db.collection1.find({name:"foo"},{_id:1})
EDIT
A call to find will return a cursor. Cursors works like an iterator in other languages. You can either attempt to find the first element in the cursor using the next() function and then get it's _id property or simplify your statement using findOne:
var x = db.collection1.findOne({name:"foo"}, {_id:1});
var id = x._id;
This is making an assumption that you are getting a document back from that query. You'll probably want to add a null check on x before grabbing the _id property.
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?
If I have a mongodb collection users like this:
{
"_id": 1,
"name": {
"first" : "John",
"last" :"Backus"
},
}
How do I retrieve name.first from this without providing _id or any other reference. Also, is it possible that pulling just the `name^ can give me the array of embedded keys (first and last in this case)? How can that be done?
db.users.find({"name.first"}) didn't work for me, I got a:
SyntaxError "missing: after property id (shell):1
The first argument to find() is the query criteria whereas the second argument to the find() method is a projection, and it takes the form of a document with a list of fields for inclusion or exclusion from the result set. You can either specify the fields to include (e.g. { field: 1 }) or specify the fields to exclude (e.g. { field: 0 }). The _id field is implicitly included, unless explicitly excluded.
In your case, db.users.find({name.first}) will give an error as it is expected to be a search criteria.
To get the name json :
db.users.find({},{name:1})
If you want to fetch only name.first
db.users.find({},{"name.first":1})
Mongodb Documentation link here
To fetch all the record details:
db.users.find({"name.first":""})
To fetch just the name or specific field:
db.users.find({{},"name.X":""});
where X can be first, last .
dot(.) notation can be used if required to traverse inside the array for key value pair as
db.users.find({"name.first._id":"xyz"});
In 2022
const cursor = db
.collection('inventory')
.find({
status: 'A'
})
.project({ item: 1, status: 1 });
Source: https://www.mongodb.com/docs/manual/tutorial/project-fields-from-query-results/