Reputation: 993
This is my Schema:
var userschema = new mongoose.Schema({
user: String,
follow: [String],
imagen: [{
title: String,
date: { type: Date, default: Date.now }
}]
});
And this is the code:
usermodel.findOne({ user: req.session.user }, function (err, user){
usermodel.aggregate({$unwind: '$imagen'},
{$match: { _id: { $in: user.follow } }},
{imagen: true},
{$sort: {'imagen.date': 1}},
function (err, images){
console.log(images);
res.render('home.ejs', {
user: user,
following: images
});
});
});
The follow
contains users's _id
.
The code works, except when I include the $match
. I use the $match
to filter the result, only getting the images of the user that I'm following, but the console.log show me that the result of the aggregate
search is undefined, but when I don't write the $match
query, I get the images, but I obtain all the images, not only the images of the user that I'm following.
Is there any solution for this...?
Thank's advance!
EDIT:
var express = require('express');
var MongoStore = require('connect-mongo')(express);
var fs = require('fs');
var mongoose = require('mongoose');
var app = express();
app.listen(9191);
var sessionStore = new MongoStore({db: 'session'});
app.configure(function(){
app.use(express.bodyParser());
app.set('views',__dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.static(__dirname + '/public'));
app.use(express.cookieParser());
app.use(express.session({
store: sessionStore,
secret: 'secret'
}));
app.use(app.router);
});
var db = mongoose.createConnection('localhost', 'test');
var userschema = new mongoose.Schema({
user: String,
follow: [String],
imagen: [{
title: String,
date: { type: Date, default: Date.now }
}]
});
var usermodel = db.model('usermodel', userschema);
var ObjectId = require('mongoose').Types.ObjectId;
app.get('/', middleware.noses, function (req, res){
res.render('home0.ejs');
});
app.get('/home', middleware.yeses, function (req, res){
usermodel.findOne({ user: req.session.user }, function (err, user){
if (user.follow.length != 0){
usermodel.find({ _id: {$in: user.follow } }, { user: true }, function (err, users){
var usernames = users.map(function(u){ return u.user });
usermodel.aggregate({$match: { _id: { $in: user.follow.map(
function(id){ return new ObjectId(id); })}}},
{$unwind: '$imagen'},
{imagen: true},
{$sort: {'imagen.date': 1}},
function (err, images){
console.log(images);
res.render('home.ejs', {
user: user,
following: images
});
});
});
} else {
res.render('home.ejs', {
user: user,
following: undefined
});
}
});
});
EDIT:
[ { __v: 4,
_id: 50fd9c7b8e6a9d087d000006,
follow: ['50fd9cbd1322de627d000006', '50fd9d3ce20da1dd7d000006'],
imagen:
[{ title: 'foo',
_id: 50fd9ca2bc9f163e7d000006,
date: Mon Jan 21 2013 20:53:06 GMT+0100 (CET) },
{ title: 'foot',
_id: 50fda83a3214babc88000005,
date: Mon Jan 21 2013 21:42:34 GMT+0100 (CET) }],
user: 'Mrmangado' }
Upvotes: 7
Views: 27637
Reputation: 312139
Mongoose doesn't do any schema-based casting of the arguments of aggregate
, so you need to convert your user.follow
array of string ids into an array of ObjectIds in the $match
:
{$match: { _id: {
$in: user.follow.map(function(id){ return new mongoose.Types.ObjectId(id); })
}}},
NOTE: Do not use mongoose.Schema.Types.ObjectId
for casting. It will not work.
You should also move this $match
to the beginning of the pipeline for efficiency.
UPDATE
Your other problem is you need to use a $project
operator instead of just including a plain {imagen: true}
object in the pipeline. Putting it all together and reordering for a more efficient pipeline, this worked for me with your data:
usermodel.aggregate(
{$match: { _id: {
$in: user.follow.map(function(id){ return new mongoose.Types.ObjectId(id); })
}}},
{$project: {imagen: true}},
{$unwind: '$imagen'},
{$sort: {'imagen.date': 1}},
function (err, images){ ...
Upvotes: 27
Reputation: 1465
To anyone who stumbles upon this question hoping for a more 'generic' solution with the need to manually .map
or do conversions/transformation manually, here a solution that may
work for you:
Requirements: Your query object for the $match must fit into some schema you've created.
General Solution:
Model.aggregate([
{ $match: Model.where(yourQueryObject).cast(QueryModel); }
]);
The catch here is Mongoose Query API's Query#cast
which can help you transforming your plain object into whatever the schema defines. This helps normalizing ObjectIDs, strings and numbers.
Possible Solution to this Question:
Considering only the $match phase:
{$match: usermodel.where({_id: { $in: user.follow }}).cast(usermodel) }}
Upvotes: 0