I am storing data of organizations in the following document structure:
{
"_id":ObjectId("52ffc33cd85242f436000001"),
"name": "NASA",
"users" : [
{
"_id" : ObjectId("5629f0b20fe85c57ed459913"),
"level" : "organization_lead"
},
{
"_id" : ObjectId("5629ff550fe85c57ed459914"),
"level" : "team_member"
}
]
}
Users are in another collection and look like this:
{
"_id" : ObjectId("5629ff550fe85c57ed459914"),
"email" : "bob#email.com",
"firstname" : "Bob",
"lastname" : "Green",
}
What would be the most efficient way to get a list of user documents belonging to a specific organization?
If I had only the _id's in the users array I would just pass that array to another query to get the users but what should I do in this situation? Or is there a better way to have a reference that has additional information?
Use the forEach() method of the find() cursor for the organisation collection to iterate over, access the documents in the loop and call the findOne() method to get the full user document of each user _id, as in the following example:
db.organisation.find({ "name": "NASA", "users.0": { "$exists": true } }).forEach(function(doc){
var updatedUsers = doc.users.map(function(u){
var user = db.users.findOne({"_id": u._id});
user["level"] = u.level;
return user;
}
doc.users = updatedUsers;
printjson(doc);
})
Use populate,
db.organisation.findOne({ "name": "NASA"}, function(err, response) {
db.Users.populate(response.user, {'path': _id, 'select': 'firstname lastname email'}, function(err, populatedUserData) {
console.log(populatedUserData);
});
});
Output will be,
[{
"_id":ObjectId("52ffc33cd85242f436000001"),
"name": "NASA",
"users" : [
{
"_id" : [{
"_id" : ObjectId("5629f0b20fe85c57ed459913"),,
"email" : "laurem#email.com",
"firstname" : "laurem",
"lastname" : "Ipsum"
}],
"level" : "organization_lead"
},
{
"_id" : [{
"_id" : ObjectId("5629ff550fe85c57ed459914"),
"email" : "bob#email.com",
"firstname" : "Bob",
"lastname" : "Green"
}],
"level" : "team_member"
}
]}]
Related
{
"_id" : ObjectId("5badfada90fd543fd8aa7f96"),
"__v" : 0,
"deleted" : false,
"groups" : [
{
"group" : "grp",
"_id" : ObjectId("5bae09a601123357e58b66a2"),
"activities" : [
ObjectId("5bae09a601123357e58b66a3"),
ObjectId("5bae10de01123357e58b66a6")
]
},
{
"group" : "123",
"_id" : ObjectId("5bae0f1001123357e58b66a4"),
"activities" : [
ObjectId("5bae0f1001123357e58b66a5")
]
}
],
"nextActivityId" : 22,
"name" : "test",
"year" : "1",
"status" : "2",
"vision" : ObjectId("5bab2f4872acf42a81c124d0")
}
The Above Schema is a "Plan" Schema
I have to write a query for removing an Activity inside "activities" array. What will be the optimum solution for this? And how will I use $pull to achieve this
This was my solution, but it will delete the complete groups array
Plan.update({ _id: PLAN ID }, { $pull: { groups: { activities: ACTIVITY ID } } })
PLAN ID BEING: "_id" : ObjectId("5badfada90fd543fd8aa7f96"),
ACTIVITY ID FOR EXAMPLE BEING: ObjectId("5bae09a601123357e58b66a3")
Thank you!
You need to use the positional $ update operator.
db.Plan.update(
{ "_id" : PLAN ID },
{ "$pull": { "groups.$.activities": ACTIVITY ID } }
)
You can try this,
db.Plan.update({ _id: ObjectId("5badfada90fd543fd8aa7f96"),"groups.activities":{$in:[ ObjectId("5bae09a601123357e58b66a3") ]}},
{ $pull: { "groups.$.activities": ObjectId("5bae09a601123357e58b66a3") } });
The positional operator did not find the match needed from the query warning when use $ only update object.
I'm newbie in mongo, so:
I have a collection 'my_collection' like this:
{
"_id" : ObjectId("5546329a470000850084a621"),
"company_name" : "Microsoft",
"type" : 'company',
}
{
"_id" : ObjectId("5546329a470000850084a622"),
"company_name" : "Google",
"type" : 'company',
}
{
"_id" : ObjectId("5546329a470000850084a623"),
"company_name" : "Apple",
"type" : 'company',
}
{
"_id" : ObjectId("5546329a470000850084a624"),
"name" : "John",
"surname" : "Smith",
"type" : 'person',
}
{
"_id" : ObjectId("5546329a470000850084a625"),
"name" : "Eugene",
"surname" : "Harper",
"type" : 'person',
"company_id" : '5546329a470000850084a622',
}
{
"_id" : ObjectId("5546329a470000850084a626"),
"name" : "Philipp",
"surname" : "Hoffman",
"type" : 'person',
"company_id" : '5546329a470000850084a622',
}
{
"_id" : ObjectId("5546329a470000850084a627"),
"name" : "Adam",
"surname" : "Jonson",
"type" : 'person',
}
{
"_id" : ObjectId("5546329a470000850084a628"),
"name" : "Bruse",
"surname" : "Willis",
"type" : 'person',
"company_id" : '5546329a470000850084a623',
}
I need to get a list of companies that have employees. (ie if an employee refers to a company, it must be listed)
I think in MySQL my query would be something like this:
SELECT * from my_collectionWHERE type = company AND (type = person AND company_id = _id)
So, in the result I expect two companies:
1. Google
2. Apple
What query it needed in mongo to get this result?
{
"_id" : ObjectId("5546329a470000850084a621"),
"company_name" : "Microsoft",
}
{
"_id" : ObjectId("5546329a470000850084a622"),
"company_name" : "Google",
}
It's wrong
$collection = $db -> my_collection->find(
array(
"type" => 'company',
"_id" => { $in: [
"type" => 'person',
"_id" => ???,
]
}
)
);
Your both the ids are different. So you are using $in is perfect. I don't know much about php but $in query takes an array of argument as parameters.
So pass ["5546329a470000850084a621", "5546329a470000850084a622"] value in $in query.
Your code will be something like this:
$collection = $db -> my_collection->find(
array(
"type" => 'company',
"_id" => { $in: ["5546329a470000850084a621", "5546329a470000850084a622"]
}
)
);
If it's not possible to convert the schema then you would need to run two queries; one to get the company ids for documents which have a person "type" with the result mapped to ObjectIds and the final to query the collection with the above ids.
Consider the following queries:
const company_ids = db.my_collection.distinct("company_id",
{ "type": "person", "name": { "$exists": true } }
).map(ObjectId);
db.my_collection.find({ "_id": { "$in": company_ids } }, { "company_name": 1 });
For an effective query which leverages the $lookup operator that can do a self-join on the same collection, you need to change your schema first i.e. cast the company_id string to ObjectId.
A couple of ways you can go about the schema conversion. For relatively large collections use the bulkWrite() method with batched updates as:
let bulkUpdateOps = [],
cursor = db.my_collection.find({ "company_id": { "$type": 2 } });
cursor.forEach(doc => {
const { _id, company_id } = doc;
let temp = new ObjectId(company_id);
bulkUpdateOps.push({
"updateOne": {
"filter": { _id },
"update": { "$set": { company_id: temp } },
"upsert": true
}
});
if (bulkUpdateOps.length === 1000) {
db.my_collection.bulkWrite(bulkUpdateOps);
bulkUpdateOps = [];
}
});
if (bulkUpdateOps.length > 0) {
db.my_collection.bulkWrite(bulkUpdateOps);
}
or for small collections as straightforward as
db.my_collection.find({ "company_id": { "$type": 2 } }).forEach(doc => {
doc.company_id = new ObjectId(doc.company_id);
db.test.save(doc);
});
After the schema conversion, you can then query using the aggregation framework which has a $lookup pipeline step that you can use to create a "self-join" of the collection, a final $match stage to query the companies with the employees and return the desired result.
Consider running the following aggregate operation:
db.my_collection.aggregate([
{
"$lookup": {
"from": "my_collection",
"localField": "_id",
"foreignField": "company_id",
"as": "employees"
}
},
{ "$match": { "employees.0": { "$exists": true } } }
])
Sample Output
/* 1 */
{
"_id" : ObjectId("5546329a470000850084a622"),
"company_name" : "Google",
"type" : "company",
"employees" : [
{
"_id" : ObjectId("5546329a470000850084a625"),
"name" : "Eugene",
"surname" : "Harper",
"type" : "person",
"company_id" : ObjectId("5546329a470000850084a622")
},
{
"_id" : ObjectId("5546329a470000850084a626"),
"name" : "Philipp",
"surname" : "Hoffman",
"type" : "person",
"company_id" : ObjectId("5546329a470000850084a622")
}
]
}
/* 2 */
{
"_id" : ObjectId("5546329a470000850084a623"),
"company_name" : "Apple",
"type" : "company",
"employees" : [
{
"_id" : ObjectId("5546329a470000850084a628"),
"name" : "Bruse",
"surname" : "Willis",
"type" : "person",
"company_id" : ObjectId("5546329a470000850084a623")
}
]
}
My Data from Mongodb
{
"_id" : ObjectId("57d718ddd4c618cbf04772d6"),
"_class" : "io.core.entity.Layer",
"name" : "u2",
"layerMembers" : [
{
"permission" : "OWNER",
"user" : {
"_id" : ObjectId("57d440c3d4c60e2f13553216"),
"nameSurname" : "User 2",
"email" : "user2#email.com"
},
"isOwner" : true
},
{
"permission" : "EDIT",
"user" : {
"_id" : ObjectId("57d44050d4c62bfdc8a9fd30"),
"nameSurname" : "User 1",
"email" : "user#email.com"
},
"isOwner" : false
}
]
}
My queries;
db.getCollection('layer').find({$and: [{"layerMembers.user._id":
ObjectId("57d440c3d4c60e2f13553216"), "layerMembers.permission":
"EDIT"}]})
db.getCollection('layer').find({$and: [{"layerMembers.user._id":
ObjectId("57d440c3d4c60e2f13553216"), "layerMembers.isOwner":
false}]})
These queries, both of them found my data, but in my opinion, it should not get this data. Because query is 'AND' query and when the user id equals "57d440c3d4c60e2f13553216", permission is "OWNER" and "layerMembers.isOwner" is true.
And also this query can find my data.
db.getCollection('layer').find({"layerMembers.user._id":
ObjectId("57d440c3d4c60e2f13553216"), "layerMembers.isOwner": false})
What is the missing part ?
You should use $elemMatch (https://docs.mongodb.com/manual/reference/operator/query/elemMatch/) if you want to only return a document where you are trying to match multiple fields within a nested array.
something like:
{
"layerMembers":
"$elemMatch": {
"user._id": ObjectId("57d440c3d4c60e2f13553216"),
"permission": "EDIT"
}
}
Here is the Structure of my MongoDB Document
{ "_id" : ObjectId("56daf32732e68d206fac1841"),
"users" : [
{
"Id" : 1,
"FirstName" : "noname",
"email" : "NoName625#gmail.com"
},
{
"Id" : 2,
"FirstName" : "abc",
"email" : "abc#abc.com"
},
{
"Id" : 3,
"FirstName" : "Krishna",
"email" : "Krishna85#gmail.com"
}
] }
And I want to perform search using FirstName as Parameters. Is it possible to get Result like this
{
"Id" : 3,
"FirstName" : "Krishna",
"email" : "Krishna85#gmail.com"
}
If I want to search using the parameters FirstName to Get Result.
Question :Write a Query for this.
You have to use the $ projection operator
https://docs.mongodb.org/manual/reference/operator/projection/positional/
db.Collection.find({ "users.FirstName": 'Krishna'} , { "users.$.FirstName" : 1 })
Result will be:
{
"_id": ObjectId("56daf32732e68d206fac1841"),
"users": [{
"Id": 3,
"FirstName": "Krishna",
"email": "Krishna85#gmail.com"
}]
}
To format result as you want it to be (if you still wants to do so), you will have to use the aggregation framework and format the result using $project
https://docs.mongodb.org/manual/aggregation/
I will to retrieved a data from MongoDb one the file to check is on a array.
I mean I have my collection "colorin" with data as:
{
"_id" : "411",
"addinon" : [
{
"key" : "0001",
"name" : "ClaroEsta"
},{
"key" : "0002",
"name" : "ClaroNOEsta"
},
]
}
so I would like to retrieve a colorin that is equial in KEY = "001"
What would be the best approach.
db.colorin.find({ addinon: { $elemMatch: { key: "001" } } });