【问题标题】:Can't use $match with mongoose and the aggregation framework不能将 $match 与 mongoose 和聚合框架一起使用
【发布时间】:2013-01-11 03:54:42
【问题描述】:

这是我的架构:

var userschema = new mongoose.Schema({

  user: String,
  follow: [String],
  imagen: [{ 

              title: String,
              date: { type: Date, default: Date.now }

           }]
 });

这是代码:

 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

                      });
   });
  });

follow 包含用户的_id

代码有效,除非我包含$match。我使用$match 过滤结果,只获取我正在关注的用户的图像,但console.log 显示aggregate 搜索的结果未定义,但是当我不写时$match 查询,我得到了图像,但我得到了所有的图像,而不仅仅是我关注的用户的图像。

有什么解决办法吗...?

感谢您的提前!

编辑:

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

            });

     }

 });
});

编辑:

[ { __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' }

【问题讨论】:

  • 你有user在unwind之前投影出来,如果你打算在unwind之后使用,编辑:读得太快,你必须把_id投影出去
  • 如何将_id 投射出去?

标签: node.js mongodb express mongoose


【解决方案1】:

Mongoose 不会对aggregate 的参数进行任何基于模式的转换,因此您需要将user.follow 字符串ID 数组转换为$match 中的ObjectId 数组:

{$match: { _id: { 
    $in: user.follow.map(function(id){ return new mongoose.Types.ObjectId(id); })
}}},

注意:不要使用mongoose.Schema.Types.ObjectId 进行投射。 它不起作用。

您还应该将此 $match 移动到管道的开头以提高效率。

更新

您的另一个问题是您需要使用$project 运算符,而不仅仅是在管道中包含一个普通的{imagen: true} 对象。将所有内容放在一起并重新排序以获得更高效的管道,这对我的数据有用:

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){ ...

【讨论】:

  • 仍然返回未定义。我需要做更多的事情吗?
  • @MrMangado 您能否编辑您的问题以包含一两个示例文档?您越容易让人们重现您的问题,就越容易完全回答。
  • 更新。我希望它会有所帮助
  • @MrMangado 谢谢,但我希望您也可以包含一个示例 usermodel 文档。
  • 注意:ObjectId 构造函数存在于两个地方:mongoose.Types.ObjectIdmongoose.Schema.Types.ObjectId。后者对我不起作用!希望对某人有所帮助。
【解决方案2】:

对于偶然发现这个问题的任何人,希望有一个更“通用”的解决方案,需要手动 .map 或手动进行转换/转换,这里有一个 may 为您工作的解决方案:

要求:$match 的查询对象必须适合您创建的某些架构。

一般解决方案

Model.aggregate([
   { $match: Model.where(yourQueryObject).cast(QueryModel); }
]);

这里的问题是 Mongoose Query API 的 Query#cast,它可以帮助您将普通对象转换为架构定义的任何内容。这有助于规范化 ObjectID、字符串和数字。

此问题的可能解决方案

仅考虑 $match 阶段:

{$match: usermodel.where({_id: { $in: user.follow }}).cast(usermodel) }}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-16
    • 2014-05-12
    • 2017-08-20
    • 2016-07-11
    相关资源
    最近更新 更多