$push into Array in Object in the document Mongoose - mongodb

How do I $push into the Array which is in the Object in the document in mongoose?
The schema looks like this
{
rating: {
usersRated: Array,
rating: Number
}
}
I have tried {rating: {$push: {usersRated: data.userId}}}, but it does not work.

You should update the collection.
In your case:
model.update({ _id: id }, { $push: { 'rating.usersRated': data.userId }}, callback);
On update, you should pass the operator before the fields.

Related

How to combine $inc and $sort operators in Mongoose

Is there a way to combine the $inc and $sort operators in Mongoose so that I can both increment a value in a nested array and sort that nested array in one operation?
I know it's possible to combine $push and $sort to push a value to a nested array and sort that nested array in one operation as such:
User.update({ _id: user },
{ $push:
{ friends:
{ $each: [...],
$sort: { challengeCount: -1 }
}
}
},
{ upsert: true }, callback);
Is there a way to do something similar when incrementing a nested value in an array? For example,
User.where({ _id: userId, "segments.id": segmentId })
.update({
$inc: { 'segments.$.count': 1 },
$sort: { 'segments.$.count': '-1' }
}, callback);
$sort is not being used correctly in the latter example, just trying to demonstrate my intentions.
Thanks!

Mongodb - aggregation of subdocument and update with the result

I have the following problem. I have found and summarized each value in a subdocument.
It gives the following [ { _id: 551fb140e4b04589d8997213, sumOfpeople: 342 } ]
I want to take the sumOfpeople and insert it to the same House( the same req.params.house_id)
House.aggregate([
{ $match: {
id: req.params.house_id
}},
{ $unwind: '$people' }, // unwind creates a doc for every array element
{ $group: {
_id: '$_id',
sumOfpeople: { $sum: '$people.nr'}
}}
], function (err, result) {
if (err) {
console.log(err);
return;
}
console.log(result);
});
This is the model that I want insert the result after the aggregation into.
module.exports = mongoose.model('House', {
id: String,
people: [{
id: String,
nr: Number
}],
sumOfpeople: Number //this is the field that I want to update after the aggregation
});
I have tried to use $set : {sumOfpeople: { $sum: '$people.nr'}}.
Is it possible to use $set inside an aggregation, or how can it be solved otherwise?
There's no way in MongoDB to write results directly into an existing document while doing an aggregation.
You've got 2 options:
retrieve the results in your application code, and then in a second query update the document.
use the $out operator, that will write the results of the aggregation into a new collection. This operation will delete all documents in the results collection and insert the new one. ( http://docs.mongodb.org/manual/reference/operator/aggregation/out/ )

Mongo group and push: pushing all fields

Is there an easy way to "$push" all fields of a document?
For example:
Say I have a Mongo collection of books:
{author: "tolstoy", title:"war & peace", price:100, pages:800}
{author: "tolstoy", title:"Ivan Ilyich", price:50, pages:100}
I'd like to group them by author - for each author, list his entire book objects:
{ author: "tolstoy",
books: [
{author: "tolstoy", title:"war & peace", price:100, pages:800}
{author: "tolstoy", title:"Ivan Ilyich", price:50, pages:100}
]
}
I can achieve this by explicitly pushing all fields:
{$group: {
_id: "$author",
books:{$push: {author:"$author", title:"$title", price:"$price", pages:"$pages"}},
}}
But is there any shortcut, something in the lines of:
// Fictional syntax...
{$group: {
_id: "$author",
books:{$push: "$.*"},
}}
You can use $$ROOT
{ $group : {
_id : "$author",
books: { $push : "$$ROOT" }
}}
Found here: how to use mongodb aggregate and retrieve entire documents
Actually you cant achieve what you are saying at all, you need $unwind
db.collection.aggregate([
{$unwind: "$books"},
{$group: {
_id: "$author",
books:{$push: {
author:"$books.author",
title:"$books.title",
price:"$books.price",
pages:"$books.pages"
}},
}}
])
That is how you deal with arrays in aggregation.
And what you are looking for to shortcut typing all of the fields does not exist, yet.
But specifically because of what you have to do then you could not do that anyway as you are in a way, reshaping the document.
If problem is that you don't want to explicitly write all fields (if your document have many fields and you need all of them in result), you could also try to do it with Map-Reduce:
db.books.mapReduce(
function () { emit(this.author, this); },
function (key, values) { return { books: values }; },
{
out: { inline: 1 },
finalize: function (key, reducedVal) { return reducedVal.books; }
}
)

MongoDB One of Each

I'd like to retrieve a mongo selector for the latest posts for each of the catagory ids I specify.
Here is an example of objects in the forumTopics collection:
{
_id: ...,
createdTime: [unix epoch timestamp],
catagory: "someid"
}
In my code, I have an array of the category IDs I would like:
catagories = ["someid", "someotherid"]
I can fetch the posts for the catagories like this:
forumTopics.find {catagory: {$in: catids}}
My question is how I can fetch just one topic object for each category, the one fetched object being the one with the greatest createdTime. I know how to fetch with a limit of 1, but I'm not sure how to get one for each category in the $in.
You can do this by using the aggregation framework:
forumTopics.aggregate( [
{ $match: { catagory: {$in: catids} } },
{ $sort: { createdTime: 1 } },
{ $group: {
_id: "$catagory",
forumTopicId: {
$last: "$_id"
}
}
}
] )

How to simply count the documents by a given criteria (mongo aggregation framework)?

I would like to simply count the documents. What would be the correct way to do the following:
db.my_collection.aggregate({
$match: { // go by the indexed field
date: {
$gte: new Date(2013,1,20),
$lte: new Date(2013,1,27)
}
}
},{
$match: { // go by some other field
someField: 'someValue'
}
},{
$count: { // $sum? $group? $anythingElse?
// ???????
}
})
You should use $group with $sum. Something like this:
$group: {
_id: null,
count: {$sum: 1}
}
SQL to Aggregation Framework mapping chart.