Group / MapReduce in moongoose 3.6.15 - mongodb

I have model Record which looks like this:
{
_id: '52278952a4bb5a7415000002',
owner_id: '52278952a4bb5a7415000001',
state: 'some_string'
}
I want to GROUP records collection by owner_id where Record.state = 'some_string' and count them for each owner. In other words I want to count all records with state = 'some_string' for each owner (specified in record as owner_id). How I can accomplish this? I searched in google for mongoose group and mongoose map/reduce but couldnt find anything that I would understand - and map reduce as I know puts results to new collection and I dont want to do this. I cant find any information in mongoose docs. Other examples contains some strange keywords in query like $project etc. Can anyone provide me good working example to this problem? It should be simple to do this I guess... I found out that there is method Model.agregate(...) method but cant find how to use it.
I use mongoose 3.6.15.

To do this with aggregate and Mongoose:
Record.aggregate([
// Filter the docs to just those you want to include
{$match: {state: 'some_string'}},
// Group by owner_id and count them per owner
{$group: {_id: '$owner_id', count: {$sum: 1}}}
], function (err, results) { ... });
Docs on aggregate can be found here. It can be intimidating at first, but spend an hour or so reading over the docs and understanding the examples and you'll get the hang of it fairly quickly.

Related

Mongodb schema, keeping a count field or counting documents from separate collection

I am facing a dilemma in my MongoDB schema design.
The site I am working on has support for comments. These comments have their own schema.
comment=
{
_id: objectId,
text: "example",
author: authorObjectId,
postId: objectId
}
Comments can be posted in Posts. Posts have their own schema also.
post=
{
_id: objectId,
title: "example",
author: authorObjectId
}
I need to add a commentCount field to the posts when I return them to the frontend.
From my understanding, there are 2 ways to go about this.
Define a commentCount in postSchema, and increment/decrement it every time I add/remove a comment using $inc
Use aggregation, (project + find) when querying posts and count the comments from the comment collection.
Which solution is better for performance? Which one is the best? I don't have many users right now but I would want to take the right approach from the beginning. Because this solution will be used in many other schemas (upvotes, karma, etc.).
Also! I have tried implementing the aggregation and I couldn't come up with a query that would be able to count documents from comments collection and use the result in the project stage.

custom sort for a mongodb collection in meteor

I have this collection of products and i want to display a top 10 products based on a custom sort function
[{ _id: 1, title, tags:['a'], createdAt:ISODate("2016-01-28T00:00:00Z") } ,
{ _id: 2, title, tags:['d','a','e'], createdAt:ISODate("2016-01-24T00:00:00Z") }]
What i want to do is to sort it based on a "magic score" that can be calculated. For example, based on this formula: tag_count*5 - number_of_days_since_it_was_created.
If the first one is 1 day old, this makes the score:
[{_id:1 , score: 4}, {_id:2, score: 10}]
I have a few ideas on how i can achieve this, but i'm not sure how good they are, especially since i'm new to both mongo and meteor:
start an observer (Meteor.observe) and every time a document is
modified (or a new one created), recalculate the score and update it
on the collection itself. If i do this, i could just use $orderBy
where i need it.
after some reading i discovered that mongo aggregate or map_reduce
could help me achieve the same result, but as far as i found out,
meteor doesn't support it directly
sort the collection on the client side as an array, but using this
method i'm not sure how it will behave with pagination (considering that i subscribe to a limited number of documents)
Thank you for any information you can share with me!
Literal function sorting is just being implemented in meteor, so you should be able to do something like
Products.find({}, {sort: scoreComparator});
in an upcoming release.
You can use the transform property when creating collection. In this transform, store the magic operation as a function.
score=function(){
// return some score
};
transformer=function(product){
product.score=score;
// one could also use prototypal inheritance
};
Products=new Meteor.Collection('products',{transform:transformer});
Unfortunately, you cannot yet use the sort operator on virtual fields, because minimongo does not support it.
So the ultimate fall-back as you mentioned while nor the virtual field sorting nor the literate function sorting are supported in minimongo is client side sorting :
// Later, within some template
scoreComparator=function(prd1,prd2){
return prd1.score()-prd2.score();
}
Template.myTemplate.helpers({
products:function(){
return Products.find().fetch().sort(scoreComparator);
}
});
i'm not sure how it will behave with pagination (considering that i subscribe to a limited number of documents)
EDIT : the score will be computed among the subscribed documents, indeed.

Can MongoDB create friend relationship with one query?

I'm writing some mongoDB queries for Friend relationship. Suppose there is a User document that looks like this:
User:
{
_id: 1
Friends: [2,3,8] // an array of identifier
}
If I want to write queries for two users to become friends, I need to write two queries:
db.Users.update({_id: x}, {$push: {Friends: y}});
db.Users.update({_id: y}, {$push: {Friends: x}});
My question is: can I combine those two above to one query? If yes, how to write it?
Actually you can't.
Because MongoDB doesn't support such the functionality, you can only write two query to achieve your goal.
afaik you can't do that in a single update but you should be interested in doing bulk updates: http://docs.mongodb.org/manual/reference/method/Bulk/

Trouble updating last document from a query

Hello I'm new to Mongodb, I am currently trying to update the last document in a query result but having trouble doing so.
I know how to get the last document using
db.collection.find().sort({$natural:-1}).limit(1)
but how do I update this? I tried doing:
db.collection.update(db.collection.find().sort({$natural:-1}).limit(1))
But that didn't work. And I don't think:
db.collection.update(query,update,option).sort({$natural:-1}).limit(1))
would do what i want. I checked the official documentation but couldn't find anything on querying only for the last document.
You can use findAndModify to perform an update that requires sorting to identify the document to update:
db.test.findAndModify({
query: {},
sort: {$natural: -1},
update: {$set: {foo: 'bar'}}
})
You can also do it this way:
var id = db.collection.find().sort({$natural:-1}).limit(1)[0]['_id'];
db.collection.update({_id: id},{...})

mongodb mapreduce groupby twice

I am new to mongodb and try to count how many distinct login users per day from existing collection. The data in collection looks like following
[{
_id: xxxxxx,
properties: {
uuid: '4b5b5c2e208811e3b5a722000a97015e',
time: ISODate("2014-12-13T00:00:00Z"),
type: 'login'
}
}]
Due to my limited knowledge, what I figure out so far is group by day first, output the data to a tmp collection and use this tmp collection to do anther map reduce and output the result to a final collection. This solution will get my collections bigger which I do not really like it. Does anyone can help me out or any good/more complex tutorials that I can follow? thanks
Rather than a map reduce, I would suggest an Aggregation. You can think of an aggregation as somewhat like a linux pipe, in that you can pass the results of one operation to the next. With this strategy, you can perform 2 consecutive groups and never have to write anything to the database.
Take a look at this question for more details on the specifics.