Can MongoDB create friend relationship with one query? - mongodb

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/

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.

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.

Query moongoDB from a redis list

If for example I keep lists of user posts in redis, for example a user has 1000 posts, and the posts documents are stored into mongodb but the link between the user and the posts is stored inside redis, I can rtetrieve the array containing all the ids of a user post from redis, but what is the efficient way to retrieving them from mongodb?
do I pass a parameter to mongoDB with the array of ids, and mongo will fetch those for me?
I don't seem to find any documentation on this, if Anyone is willing to help me out!
thanks in advance!
To retrieve a number of documents per id, you can use the $in operator to build the MongoDB query. See the following section from the documentation:
http://docs.mongodb.org/manual/reference/operator/query/in/#op._S_in
For instance you can build a query such as:
db.mycollection.find( { _id : { $in: [ id1, id2, id3, .... ] } } )
Depending on how much ids will be returned by Redis, you may have to group them in batch of n items (n=100 for instance) to run several MongoDB queries. IMO, this is a bad practice to build such query containing more than a few thousands ids. It is better to have smaller queries but accept to pay for the extra roundtrips.

Group / MapReduce in moongoose 3.6.15

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.

MongoDB - Query embbeded documents

I've a collection named Events. Each Eventdocument have a collection of Participants as embbeded documents.
Now is my question.. is there a way to query an Event and get all Participants thats ex. Age > 18?
When you query a collection in MongoDB, by default it returns the entire document which matches the query. You could slice it and retrieve a single subdocument if you want.
If all you want is the Participants who are older than 18, it would probably be best to do one of two things:
Store them in a subdocument inside of the event document called "Over18" or something. Insert them into that document (and possibly the other if you want) and then when you query the collection, you can instruct the database to only return the "Over18" subdocument. The downside to this is that you store your participants in two different subdocuments and you will have to figure out their age before inserting. This may or may not be feasible depending on your application. If you need to be able to check on arbitrary ages (i.e. sometimes its 18 but sometimes its 21 or 25, etc) then this will not work.
Query the collection and retreive the Participants subdocument and then filter it in your application code. Despite what some people may believe, this isnt terrible because you dont want your database to be doing too much work all the time. Offloading the computations to your application could actually benefit your database because it now can spend more time querying and less time filtering. It leads to better scalability in the long run.
Short answer: no. I tried to do the same a couple of months back, but mongoDB does not support it (at least in version <= 1.8). The same question has been asked in their Google Group for sure. You can either store the participants as a separate collection or get the whole documents and then filter them on the client. Far from ideal, I know. I'm still trying to figure out the best way around this limitation.
For future reference: This will be possible in MongoDB 2.2 using the new aggregation framework, by aggregating like this:
db.events.aggregate(
{ $unwind: '$participants' },
{ $match: {'age': {$gte: 18}}},
{ $project: {participants: 1}
)
This will return a list of n documents where n is the number of participants > 18 where each entry looks like this (note that the "participants" array field now holds a single entry instead):
{
_id: objectIdOfTheEvent,
participants: { firstName: 'only one', lastName: 'participant'}
}
It could probably even be flattened on the server to return a list of participants. See the officcial documentation for more information.