How to retrieve array of specific field of sub document- mongodb - mongodb

This is my first mongodb project,I have this document structure in mongodb, I am trying to retrieve a particular user account (each user account has an array of contacts), from this user account, I will then obtain an array of the ID fields of the users contacts and then pass this array as a parameter to another query, I am doing this to avoid having to loop through the users contacts array in order to obtain the ID fields, here is the document structure, the query I tried is below it
{
name,
id,
contacts:[{
contactId, //I need an array of this field
dateAdded
},
contactId,
dateAdded
},
{}..]
}
//
var findByIdAll = function(accountId, callback) {
var self=this;
//Get the user account
Account.findOne({_id:accountId}, function(err,doc) {
/ After the user account has been obtained, the function below will
// use an array of the users contactsId's to fetch the contact's accounts
//please how do I obtain the array of contact Id's before reaching here
self.Account.find({_id:{$in:[/array of contact Ids]}},function(err,results){
callback(results);
});
});
};
EDIT
//I have now been able to obtain an array of contactID fields using the following query
var r=db.accounts.aggregate({$match:{email:'m#live.com'}},{$unwind:"$contacts"},
{$project:{_id:0,contacts:1}},{$group:{_id:'$_id',
list:{$push:'$contacts.accountId'}}});
The result I get from the query is
r
{
"result" : [
{
"_id" : null,
"list" : [
ObjectId("51c59a31c398c40c22000004"),
ObjectId("51c59a31c398c40c22000004")
]
}
],
"ok" : 1
}

A normal MongoDB query will always give you the entire document with the same structure.
If you want to get just part of the document or make a transformation to it you need to use the Aggregation Framework (is not as hard to understand as it looks, give it a try).
In your case you might have to use $unwind in contacts to explode the array, $match to get only the account you want, and $project to present the data as you want.

Related

How to trim a value by a particular length and then apply lookUp in mongoDB

The main issue i'm facing is doing multi document joins. For example, when I try and run a query on orders by customer I can't find an easy way to join orders to customers on a customer id because in the orders object the customer id has _user$ appended to the beginning of the user ID and I don't know how to truncate that in an aggregation pipeline.
eg; In the order object, the customer is defined as _p_customer:"_User$8qXjk40eOd"
But in the user table the _id is just 8qXjk40eOd and therfore the default lookup function in charts cannot match the two.
Note: I'm using parse server and it stores pointers in the above mentioned way.
This is how the data is being stored in the mongoDB order collection.
customer field in the above image is the pointer to the _User collection
This is how the data is stored in the mongoDB _User collection.
My requirement is to write mongo query that find all users and their related orders count. I'm not able to do that because I don't how to remove _User$ from the order row and join it the _User via _id.
before lookup in aggregate substr the field you want to use in $lookup
db.collection.aggregate([
{
$addFields :{
nUser : { $substr: [ "$_p_customer", 6, -1 ] } // _User$ has 6 characters
}
},
{
$lookup :{
from:"usersCollection",
localField:"nUser",
foreignField : "_id",
as : "UserObject"
}
}
])

Search for data in an array in a document in mongo

I have a collection organization with field
users: [
{
"user_id":"1",
"role":"1"
},
{
"user_id":"2",
"role":"2"
}]
and another collection users with fields
{
{"user_id":1},
{"user_id":2},
{"user_id":3},
{"user_id":4}
}
I need to display all users with user id present in the users array in the organizations collection. What is the best way to implement this?
if you just want to display the user_id of the users in the organization you have to unwind users field and do the project on user_id field like below.
collection.aggregate([{"$unwind","$users"},{"$project":{"user_id":"$users.user_id"}}])
db.myDbCollection.find({}, {"user_id": 1});
can use this statement to find data from your collection.

Using "$and" and "$in" together

I have a collection friends which i am using to store all the friends and has the following fields
id , userid, friendid
I have a collection notes which stores user notes and has the following fields
id, userid , ownerid , privateorpublic
The rule is a user can only see notes he/she has created or notes created by his/her friends or notes that are public
To fetch that information i am writing my query this way. First, get all the ids of my friends separated by a comma. I dont know how to write the query to return comma delimited values but this query below I am hoping will return all the firneds of the user by the given id:
db.friends.find({ { friendid: { userid: 'jhdshh37838gsjj' } }
then get the notes where are either created by a friend or are public notes or are notes belonging to user
db.notes.find({ownerid:'jhdshh37838gsjj', privateorpublic:'public',{ $in: [ "3ghd8e833", "78hhyaysgd" ] }
I am new to MongoDB. Are my queries right?
Find query syntax : db.collection.find({queryFieldName: queryFieldValue}, {requiredFieldName: 1, NotRequiredFieldName: 0})
Thus, translating first query, you'd get "get me all documents from collection friends where friendId equals a string {'userId':'Id'}" which is not desired.
Query for "Get me all friend Ids of userid jhdshh37838gsjj and don't print anything else in results" : db.collection.find({userId:'jhdshh37838gsjj'}, {friendId:1, _id:0})
However, this'll not give output as comma separated values. You'll get output as follows (because every document is an independent object):
{friendId: 1}
{friendId: 2}
$in requires array as input and not comma separated values. To make an array of field values for a $in query, you need to some extra work like:
var friendIdsArr = [] //Initiate an array to store friend Ids
db.friends.find({'userId':'jhdshh37838gsjj'},{'friendId':1,'_id':0}).forEach(function(x) {friendIdsArr.push(x.friendId);} ); //Foreach result in query, push value to array.
The friendIdsArr will be [1,2]
db.notes.find({'ownerId':'jhdshh37838gsjj', 'privateOrPublic':'public',{$in: ["friendId": friendIdsArr]})
will give results, json documents, matching the given conditions.
Interestingly, your notes collection doesn't have a note field.
I'd recommend you to read mongodb official documentation and make a single query instead of two different queries.

Composition in mongo query (SQL sub query equivalent)

I have a couple of collections, for example;
members
id
name
//other fields we don't care about
emails
memberid
//other fields we don't care about
I want to delete the email for a given member. In SQL I could use a nested query, something like;
delete emails
where memberid in (select id from members where name = "evanmcdonnal")
In mongo I'm trying something like this;
db.emails.remove( {"memberid":db.members.find( {"name":"evanmcdonnal"}, {id:1, _id:0} ) )
But it returns no results. So I took the nested query and ran it on it's own. The issue I believe is that it returns;
{
"id":"myMadeUpId"
}
Which - assuming inner queries execute first - gives me a query of;
db.emails.remove( {"memberid":{ "id""myMadeUpId"} )
When really I just want the value of id. I've tried using dictionary and dot notation to access the value of id with no luck. Is there a way to do this that is similar to my attempted query above?
Let's see how you'd roughly translate
delete emails where memberid in (select id from members where name = "evanmcdonnal")
into a set of mongo shell operations. You can use:
db.members.find({ "name" : "evanmcdonnal" }, { "id" : 1 }).forEach(function(doc) {
db.emails.remove({ "memberid" : doc.id });
});
However, this does one remove query for each result document from members. You could push the members result ids into an array and use $in:
var plzDeleteIds = db.members.find({ "name" : "evanmcdonnal" }, { "id" : 1 }).toArray();
db.emails.remove({ "memberid" : { "$in" : plzDeleteIds } });
but that could be a problem if plzDeleteIds gets very, very large. You could batch. In all cases we need to do multiple requests to the database because we are querying multiple collections, which always requires multiple operations in MongoDB (as of 2.6, anyway).
The more idiomatic way to do this type of thing in MongoDB is to store the member information you need in the email collection on the email documents, possibly as a subdocument. I couldn't say exactly if and how you should do this since you've given only a bit of your data model that has, apparently, been idealized.
As forEach() way didn't work for me i solved this using:
var plzDeleteIds = db.members.find({ "name" : "evanmcdonnal" }, { "id" : 1 }).toArray();
var aux = plzDeleteIds["0"];
var aux2 = aux.map(function(u) { return u.name; } );
db.emails.remove({ "memberid" : { "$in" : aux2 } });
i hope it help!
I do not believe what you are asking for is possible. MongoDB queries talk to just one collection -- there is no syntax to go cross-collection.
However, what about the following:
The name in members does not seem to be unique. If you were to delete emails from the "emails' collection using name as the search attribute, you might have a problem. Why not store the actual email address in the email collection? And store email address again in the members collection. When your user logs in, you will have retrieved his member record -- including the email address. When you want to delete his emails, you already have his email and you can do:
db.emails.remove({emailAddress: theActualAddress))
Does that work?

Document References query example

If I choose to use Document References with a structure of Materialized Paths instead of the simple Embedded Documents how can I display the same results?
For example if I had Embedded docs I simply :
db.col.find({'user' : 'foo'})
and return:
{'user' : 'foo',
'posts' : [ {},
{},
{}
]
}
Which command should I use to display posts as an embedded array of that user? Or this can only happen client-side?
If it's document references,
users collection will contain:
{
_id : "foo",
// users details
}
and posts collection:
{
_id: "postid",
author: "foo"
// other fields
}
In this case,
1) First make query to get the user id from users collection.
2) Then send the user id to the posts collection to get all posts
var user = db.users.find({_id : "foo"});
// this is used to get user details or validate user and only after validation if you need to fetch the posts
var posts = db.posts.find({author: user._id });
As the documents are referenced, there will be a roundtrip to the server which is obvious.
I am not sure how you have used materialized path for this scenario, let me know the data structure of it and i would be able to mention the query based on that.