Retrieve only the queried element in an object array - mongodb

I have a collection with organizations. Each organization has members. I want to run query to check if a user is a member of that organization.
I tried this:
mongoose.model('organization').find({orgId: paramOrgId}, function(err, organization){
organization.find({'members.user':req.user._id}, function(err, user){
if(!user) res.send(401) //The user is not a member in organization
if(user) res.send(200);
});
}
return res.send(401);
});
Apparently you don't have 'find' on callback. How should I do this instead?
Example of organization doc:
> db.organizations.find().forEach(printjson);
{
"_id" : ObjectId("5381d5d11409f125475fcc90"),
"orgId" : 5,
"title" : "ExampleCorp",
"members" : [
{
"tier" : 1,
"user" : ObjectId("5381d5d11409f125475fcc8c")
},
{
"tier" : 2,
"user" : ObjectId("5381d5d11409f125475fcc8d")
},
{
"tier" : 3,
"user" : ObjectId("5381d5d11409f125475fcc8e")
}
]
}

Here it is in one query if you just want to check if a user is a member of an organization.
// Use findOne so that it returns one document instead of a collection
mongoose.model('organization').findOne({
// Instead of querying twice, just set both conditions
'orgId': paramOrgId,
'members.user':req.user._id
},
'_id', // We'll just select the _id field. We don't need the whole organization document
function (err, org) {
if (err)
return res.send(500); // Error!
if (org)
return res.send(200);
else
return res.send(401);
});

Related

How to find and update a mongoose model?

I have a model userDatas and it contain a list of user data.
[{
"_id" : ObjectId("5bb6730721f28a295436b36f"),
"userId" : "5bb6730721f28a295436b36e",
"reputationNumber" : 0,
"questions" : [],
"answers" : []
},
{
"_id" : ObjectId("5bb6738c21f28a295436b371"),
"userId" : "5bb6738c21f28a295436b370",
"reputationNumber" : 0,
"questions" : [],
"answers" : []
}]
I want to filter by userId and add "5bb7d72af050ca0910282ff4" string to questions array. How to accomplish that?
//Userdatas.find
Since you are using mongoose you can use the findOneAndUpdate and addToSet to achieve this:
Userdatas.findOneAndUpdate(
{userId: "5bb7d72af050ca0910282ff4"},
{$addToSet: {questions: '5bb7d72af050ca0910282ff4'}},
function (err, result) {
...
}
)
The query would look something like
Userdatas.findOne({where: {userId: "5bb7d72af050ca0910282ff4"}}, function (err, data) {
if (!err && data) {
var questionsArr = [];
if (data.questions) {
questionsArr = data.questions;
}
questionsArr.push('5bb7d72af050ca0910282ff4');
data.updateAttributes({questions: questionsArr}, function(err, updateData) {
cb (err, updateData);
});
} else {
cb (err, {});
}
});
Unfortunately you would need 2 queries to do this. First, to get the document where the userId matches your required userId and to push the string to the questions array and update the document.
EDIT:
The first findOne query fetches the document where userId matches our user. The updateAttributes query is executed on the document that was fetched, so it updates the correct document.

Find records with field in a nested document when parent fields are not known

With a collection with documents like below, I need to find the documents where a particular field - eg. lev3_field2 (in document below) is present.
I tried the following, but this doesn't return any results, though the field lev3_field2 is present in some documents.
db.getCollection('some_collection').find({"lev3_field2": { $exists: true, $ne: null } })
{
"_id" : ObjectId("5884de15bebf420cf8bb2857"),
"lev1_field1" : "139521721",
"lev1_field2" : "276183",
"lev1_field3" : {
"lev2_field1" : "4",
"lev2_field2" : {
"lev3_field1" : "1",
"lev3_field2" : {
"lev4_field1" : "1",
"lev4_field2" : "1"
},
"lev3_field3" : "5"
},
"lev2_field3" : {
"lev3_field3" : "0",
"lev3_field4" : "0"
}
}
}
update1: this is an example, however in the real document it is not known what the parent fields are for the field to look for. So instead of lev3_field2 , I would be looking for `levM_fieldN'.
update2: Speed is not a primary concern for me, I can work with relatively a bit slower options as well, as the primary function is to find documents with the criteria discussed and once the document is found and the schema is understood, the query can be re-written for performance by including the parent keys.
To search a key in nested document you need to iterate the documents fields recursively, you can do this in JavaScript by the help of $where method in MongoDB
The below query will search if a key name exists in a documents and its subdocuments.
I have checked this with the example you have given, and it is working perfectly fine.
db.getCollection('test').find({ $where: function () {
var search_key = "lev3_field2";
function check_key(document) {
return Object.keys(document).some(function(key) {
if ( typeof(document[key]) == "object" ) {
if ( key == search_key ) {
return true;
} else {
return check_key(document[key]);
}
} else {
return ( key == search_key );
}
});
}
return check_key(this);
}}
);
There is no built-in function to iterate over document keys in MongoDB, but you can achieve this with MapReduce. The main advantage is that all the code is executed directly in the MongoDB database, and not in the js client, so there is no network overhead, hence it should be faster than client side js
here is the script :
var found;
// save a function in MongoDB to iterate over documents key and check for
// key name. Need to be done only once
db.system.js.save({
_id: 'findObjectByLabel',
value: function(obj, prop) {
Object.keys(obj).forEach(function(key) {
if (key === prop) {
found = true
}
if (!found && typeof obj[key] === 'object') {
findObjectByLabel(obj[key], prop)
}
})
}
})
// run the map reduce fonction
db.ex.mapReduce(
function() {
found = false;
var key = this._id
findObjectByLabel(this, 'lev3_field2')
value = found;
if (found) {
// if the document contains the key we are looking for,
// emit {_id: ..., value: true }
emit(key, value)
}
},
function(key, values) {
return values
}, {
'query': {},
'out': {inline:1}
}
)
this output ( run on 4 sample doc, with only one containing 'lev3_field2' )
{
"results" : [
{
"_id" : ObjectId("5884de15bebf420cf8bb2857"),
"value" : true
}
],
"timeMillis" : 18,
"counts" : {
"input" : 4,
"emit" : 1,
"reduce" : 0,
"output" : 1
},
"ok" : 1
}
to run the script, copy it to a file name "script.js" for example, and then run from your shell
mongo databaseName < script.js
It's because you're trying to see if a nested field exists. This is the query you want:
db.some_collection.find({"lev1_field3.lev2_field2.lev3_field2": { $exists: true, $ne: null } })

Why does my list of items sort incorrectly after many multiple updates?

I'm using Meteor, and I have a list of items like:
Todo A
Todo B
Todo C
Todo D
But then after calling multiple updates one after another:
Todos.find().forEach(function(todo) {
Todos.update(todo._id, {$set: {
strength:s,
retention:r,
}},
function(err, res){
if(err){throw err}
console.log('updated '+res+' doc');
})
})
Todo A
Todo D
Todo C
Todo B
the list order becomes messed up. If I refresh it's fine again and sorted accordingly. Why could this be?
Template.listsShow.helpers({
editing: function() {
return Session.get(EDITING_KEY);
},
todosReady: function() {
return Router.current().todosHandle.ready();
},
todos: function(listId) {
var obj = Todos.find({listId: listId}, {sort: {createdAt : 1}});
return obj;
}
});
//Server Side
Meteor.publish('todos', function(listId) {
check(listId, String);
return Todos.find({listId: listId});
});
{
"_id" : "6pELT5pmGoXQhh2eG",
"createdAt" : ISODate("2016-01-02T23:58:12.236Z")
}
{
"_id" : "4ES3hbJX76nLCJGGL",
"createdAt" : ISODate("2016-01-02T23:58:12.236Z")
}
{
"_id" : "NzModCoCHcbWdWo22",
"createdAt" : ISODate("2016-01-02T23:58:12.236Z")
}
{
"_id" : "tzgK3EdMrBi8SbGBn",
"createdAt" : ISODate("2016-01-02T23:58:12.236Z")
Based on our conversation above, it looks like the issue had to do with the fact that several of the documents had the same value for createdAt. Therefore sorting on that field alone would result in an arbitrary ordering. If the documents were generated from a script, you could try randomizing the date. Additionally, you could sort on more than one field, for example: {sort: {createdAt: 1, message: 1}}.

Mongodb: Finding and updating object property from array

I have a collection with multiple documents which follow this structure:
{
"_id" : {
"oid" : XXX
},
"name" : "Name",
"videos" [
{
"id" : 1,
"thumbnail" : "thumbnail.jpg",
"name" : "Name here"
},
{
"id" : 2,
"thumbnail" : "thumbnail.jpg",
"name" : "Name here"
},
{
"id" : 3,
"thumbnail" : "thumbnail.jpg",
"name" : "Name here"
}
]
}
I want to find and update the a thumbnail of a video, of which I only know the id, but not which document it is in.
This is what I've tried so far, but it's not working properly. All the examples I found relied on knowing the document id, and the array position of the object to update. I also found that doing a query like this found the document okay, but set the whole document as the new thumbnail!
db.collection(COLLECTION-NAME, function(err, collection){
collection.update(
{ 'videos.id' : 2 },
{ $set: { thumbnail: "newThumbnail.jpg" } },
function(err, result){
if (!err){
console.log('saved', result)
} else {
console.log('error', err);
}
}
);
});
Use the $ positional operator to update the value of the thumbnail field within the embedded document having the id of 2:
db.collection.update(
{ "videos.id": 2 },
{ "$set": { "videos.$.thumbnail" : "newThumbnail.jpg" } }
)

Mongodb update subdocument inside array field of a collection

I have a mongodb collection like
{
"_id" : ObjectId("5375ef2153bb790b20d8a660"),
"association" : [
{
"count" : 3,
"name" : "hayatdediğin"
},
{
"count" : 2,
"name" : "sadecesenolsan"
},
{
"count" : 2,
"name" : "üslupnamustur"
}
],
"tag_count" : 4,
"tag_name" : "vazgeçilmezolan",
"variation" : [
{
"count" : 4,
"name" : "VazgeçilmezOlan"
}
]
}
Each collection consists of tag_name, tag_count, array field association and array field variation. For each name inside association, there exists a different document same as this document. I need to add new field "total_count" inside each association dictionary whose value equals the tag_count of the name by querying the database.
I tried this code but its not working
db.hashtag.find().forEach(function (doc) {
if (doc.association.length != 0 ) {
doc.association.forEach(function (assoc) {
db.hashtag.find({'tag_name': assoc.name}).forEach(function(tag){
assoc.total_count=tag.tag_count;
})
});
}
});
After modifying each doc you need to call save on the collection to commit the change.
Assuming you're doing this in the shell:
db.hashtag.find().forEach(function (doc) {
if (doc.association.length != 0 ) {
doc.association.forEach(function (assoc) {
db.hashtag.find({'tag_name': assoc.name}).forEach(function(tag){
assoc.total_count=tag.tag_count;
});
});
// Save the changed doc back to the collection
db.hashtag.save(doc);
}
});
To update doc in database you have to use db.hashtag.update, not db.hashtag.find. Find only retrieves document from db.
I changed the previous method of looping using forEach and then saved the doc at last and the code worked.
db.hashtag.find().forEach(function (doc) {
var array = doc.association;
if (array != undefined){
for(var i=0;i<array.length;i++)
{
var obj = db.hashtag.findOne({'name':array[i].name});
var count = obj.count;
doc.association[i].total_count = count;
db.hashtag.save(doc);
}
}
});