Use $slice only in Aggregation in Mongodb - node.js

I have Database Employee Model like:
{
"_id" : ObjectId("svdfvdfvfvdf dfv "),
"name" : "XXXXXX",
"code" : "XXXXX",
"phone" : "XXXXXXX",
"email" : "XXXXXXX",
"EmpDb_Emp_id" : 7,
"organization" : ObjectId("wwwwwwwww444cdc"),
"shiftType" : ObjectId("2323232323232")
}
the data which i receive in aggregate is also an array So want TO retrive data from that .
I want to use $slice only in aggregate. So, that I want to implement Pagination in it.
Any help will be appreciated.
Thanks

Related

MongoDB DBRefs to query reference collection field

I have two different collection in two different MongoDB databases.
Collection users in db1:
{
"_id" : "xyz",
"name" : "John",
"project_id" : "abc"
}
Collection project in db2:
{
"_id" : "abc",
"regionCode" : "1AB"
}
Now I want to get list of all users who belong to region 1AB. How do I achieve that.
I read about DBRefs. So I changed structure of collections users but still i can not query directly to reference collection attribute directly
collection users new structure :
{
"_id" : "xyz",
"name" : "John",
"project_id" : "abc",
"projectData" : {
"$ref" : "project",
"$id" : "abc",
"$db" : "db2"
}
}
Now how do I get list of all users that belong to project regioncode 1AB.
I am using nodejs native client

Updating a specific doc in array in subdocument in MongoDb

I have a document user that have a schema as:
{
"_id" : ObjectId("57b2d706f61d04e8d99dd983"),
"addressesAsVendor" : [
{
"_id" : "V1",
"addressLine1" : "al1",
"addressLine2" : "al2",
"street" : "street",
"city" : "city",
"country" : "IN",
"pincode" : "490020",
"location" : {
"latitutde" : "lat1",
"longitude" : "lon1"
}
},
{
"_id" : "V2",
"addressLine1" : "al1",
"addressLine2" : "al2",
"street" : "street",
"city" : "city",
"country" : "IN",
"pincode" : "490020",
"location" : {
"latitutde" : "lat2",
"longitude" : "lon2"
}
}
]
}
Now let's suppose I want to update the V1 id of the addressesAsVendor array which is inside the user Id 57b2d706f61d04e8d99dd983 with the data:
{
"addressLine1" : "al1 new",
"addressLine2" : "al2 new",
"street" : "street new",
"city" : "city new",
"country" : "IN new",
"pincode" : "490020 new",
"location" : {
"latitutde" : "lat1 new",
"longitude" : "lon1 new"
}
}
So the new user doc will look like:
{
"_id" : ObjectId("57b2d706f61d04e8d99dd983"),
"addressesAsVendor" : [
{
"_id" : "V1",
"addressLine1" : "al1 new",
"addressLine2" : "al2 new",
"street" : "street new",
"city" : "city new",
"country" : "IN new",
"pincode" : "490020 new",
"location" : {
"latitutde" : "lat1 new",
"longitude" : "lon1 new"
}
},
{
"_id" : "V2",
"addressLine1" : "al1",
"addressLine2" : "al2",
"street" : "street",
"city" : "city",
"country" : "IN",
"pincode" : "490020",
"location" : {
"latitutde" : "lat2",
"longitude" : "lon2"
}
}
]
}
How this can be achieved in MongoDb and what's the best way of keeping multiple addresses, which can be easily shown in the Address page of the user and also minimum in load, I mean will be easy to access when required.
Please shed your views.
:)
You can do the update using the positional $ operator:
var data = {
"addressLine1" : "al1 new",
"addressLine2" : "al2 new",
"street" : "street new",
"city" : "city new",
"country" : "IN new",
"pincode" : "490020 new",
"location" : {
"latitutde" : "lat1 new",
"longitude" : "lon1 new"
}
};
collection.update(
{ "addressesAsVendor._id" : "V1" },
{ "$set": { "addressesAsVendor.$": data } },
function(err, result) {
if (err) return handleError(err);
console.log(result);
}
)
The positional operator in the above saves the index (0 in the case above) of the element from the array that matched the query. This means that if you knew the position of the element beforehand (which is nearly impossible in a real life case), you could just change the update statement to: { "$set": { "addressesAsVendor.0": data } }.
Since the positional $ operator acts as a placeholder for the first element that matches the query document, and the array field must appear as part of the query document hence the query { "addressesAsVendor._id" : "V1" } is essential to get the $ operator to work properly.
Please note that the positional $ operator (for now) updates the first relevant document ONLY, there is a JIRA ticket for this.
For your follow-up question which seeks to find the best way of keeping multiple addresses, which can be easily shown in the Address page of the user and also minimum in load:
Your current schema is a better approach than creating a separate collection of addresses since separate collections require more work i.e. finding a user + its addresses is two queries and requires extra work whereas the above schema embedded documents are easy and fast (single seek). There are no big differences for inserts and updates. So, separate collections are good if you need to select individual documents, need more control over querying, or have huge documents. Embedded documents are good when you want the entire document, the document with a $slice of the embedded addressesAsVendor, or with no addresses at all.
As a general rule, if you have a lot of "addresses" or if they are large, a separate collection might be best.
Smaller and/or fewer documents tend to be a natural fit for embedding.
You can use updateOne (MongoDB query) to update the document.
NodeJS equivalent is:-
collection.update(criteria, update[[, options], callback]);
Please change the object id accordingly.
db.address.updateOne({ "_id" : ObjectId("57c04425c400a6b59c9bc1ee"), "addressesAsVendor._id" : "V1" }, { $set: { "addressesAsVendor.$.addressLine1" : "al1 new",
"addressesAsVendor.$.addressLine2" : "al2 new",
"addressesAsVendor.$.street" : "street new",
"addressesAsVendor.$.city" : "city new",
"addressesAsVendor.$.country" : "IN new",
"addressesAsVendor.$.pincode" : "490020 new",
"addressesAsVendor.$.location" : {
"latitutde" : "lat1 new",
"longitude" : "lon1 new"
}
} });

Querying a property that is in a deeply nested array

So I have this document within the course collection
{
"_id" : ObjectId("53580ff62e868947708073a9"),
"startDate" : ISODate("2014-04-23T19:08:32.401Z"),
"scoreId" : ObjectId("531f28fd495c533e5eaeb00b"),
"rewardId" : null,
"type" : "certificationCourse",
"description" : "This is a description",
"name" : "testingAutoSteps1",
"authorId" : ObjectId("532a121e518cf5402d5dc276"),
"steps" : [
{
"name" : "This is a step",
"description" : "This is a description",
"action" : "submitCategory",
"value" : "532368bc2ab8b9182716f339",
"statusId" : ObjectId("5357e26be86f746b68482c8a"),
"_id" : ObjectId("53580ff62e868947708073ac"),
"required" : true,
"quantity" : 1,
"userId" : [
ObjectId("53554b56e3a1e1dc17db903f")
]
},...
And I want to do is create a query that returns all courses that have a specific userId in the userId array that is in the steps array for a specific userId. I've tried using $elemMatch like so
Course.find({
"steps": {
"$elemMatch": {
"userId": {
"$elemMatch": "53554b56e3a1e1dc17db903f"
}
}
}
},
But It seems to be returning a empty document.
I think this will work for you, you have the syntax off a bit plus you need to use ObjectId():
db.Course.find({ steps : { $elemMatch: { userId:ObjectId("53554b56e3a1e1dc17db903f")} } })
The $elemMatch usage is not necessary unless you actually have compound sub-documents in that nested array element. And also is not necessary unless the value being referenced could possibly duplicate in another compound document.
Since this is an ObjectId we are talking about, then it's going to be unique, at least within this array. So just use the "dot-notation" form:
Course.find({
"steps.userId": ObjectId("53554b56e3a1e1dc17db903f")
},
Go back and look at the $elemMatch documentation. In this case, the direct "dot-notation" form is all you need

How to get the double quotes arround number typed field from MongoDB aggregation query result?

Scenario: I have a collection 'People' with following documents
{
"_id" : ObjectId("512bc95fe835e68f199c8686"),
"name": "David",
"age" : 78
},
{ "_id" : ObjectId("512bc962e835e68f199c8687"),
"name" : "Dave",
"age" : 35
}
When I query using following code from Node.js
db.articles.aggregate(
{ $match : { author : "Dave" } }
);
The output will be like:
{ "_id" : ObjectId("512bc962e835e68f199c8687"),
"name" : "Dave",
"age" : 35
}
Issues: The above is just a sample of the actual scenario, I want the 'age' filed value to be embedded in double quotes i.e for above quoted example it should be like "age": "35".
That is full resultant document should be like following:
{ "_id" : ObjectId("512bc962e835e68f199c8687"),
"name" : "Dave",
"age" : "35"
}
Consider I have huge number of documents how efficiently I can achieve the same to get the desired output?
Question: Can someone help out with bright and efficient way to achieve the same?

Upsert embedded object in mongoDB

Given this Person collection:
{
"_id" : ObjectId("4f8e95a718bcv9c74da1e6511a"),
"name" : "John",
"hobbies" : [{
"id" : 001,
"name" : "reading",
"location" : "home"
},{
"id" : 002,
"name" : "sport",
"location" : "outside"
}]
}
and these new/edited Hobby objects:
{
"name" : "walking",
"location" : "outside"
}
and
{
"id" : 001,
"name" : "reading",
"location" : "outside"
}
If I know the Person that I want to manage, what is be the best way to upsert embedded objects?
Currently my approach is to find the Person object, make the required modifications to it in my code, and then save it back to the DB. This works. But I'd like to simplify and reduce the number of round trips to the database.

Resources