Node.js / Mongoose – 过滤嵌套的文档

长时间的听众第一次来电:-)

我search了相当长的时间,并没有完全find我的问题在这里的答案。 我正在寻找一种方法,或者想知道“正确”的方式,只返回一个嵌套mongoose模式内的特定项目。

所以,让我说我有这个例子。

var mongoose = require('mongoose') var Schema = mongoose.Schema var conn = mongoose.connect('mongodb://localhost/testjs'); Bar = new Schema({ text: String }); Foo = new Schema({ bar: [Bar] }); var Foo = mongoose.model('Foo', Foo); // Clean up the DB Foo.find({}, function(err, res) { for (i in res) { res[i].remove() } }); var foo = new Foo() foo.bar.push({"text":"Hi"}) foo.bar.push({"text":"Bye"}) foo.bar.push({"text":"Hey"}) foo.save( function(err){ var r = Foo .where('bar.text').equals('Hi') .select('bar.text') .exec(function(err, res) { console.log(res) }) } ); 

结果

 [ { _id: 546c235cea0f16dc0d85a60f, bar: [ { text: 'Hi' }, { text: 'Bye' }, { text: 'Hey' } ] } ] 

从查询中,我会希望它只能返回

 [ { _id: 546c235cea0f16dc0d85a60f, bar: [ { text: 'Hi' } ] } ] 

所以我想这引出了几个问题:

  1. 有没有更好的方式来构build这个查询?
  2. 这是典型的行为,它是要循环的结果,只是拔出我所需要的?
  3. 对于原始查询,为什么它会返回所有的字段,而不是我在'where'语句中指定的字段?

这是典型的行为

是的,这是mongodb如何执行projection操作。

.where("bar.text").equals("Hi") ,这部分查询称为find()部分。 它匹配所有的logging,具有bar.text的值为Hi

对于原始查询,为什么它会返回所有的字段,而不是我在'where'语句中指定的字段?

.select("bar.text") ,这是projection部分。 只投射我们想要的那些字段。这对除数组内的字段以外的字段的预期工作,因为在特定的深度,将只存在一个唯一的 field 。 但是在数组的情况下,可以有相同深度的“n”个文档具有相同的字段。 投影数组元素时,将显示在该级别具有该特定字段的所有子文档。 这是非常有意义的。

而且这是循环的结果,只是拔出我所需要的?

没有。下面有更好的解释。

有没有更好的方式来构build这个查询?

如果您确定数组中只包含一个匹配查询条件的文档,则可以使用$ (位置投影)运算符。

 foo.save( function(err){ var r = Foo.find({'bar.text':'Hi'},{'bar.$':1},function(err, res) { console.log(res) });}); 

如果您不确定数组中有多less个文档,并且字段值为Hi ,则可以使用聚合运算符pipe道,如下所示:

  foo.save( function(err){ var r = Foo.aggregate([ {$match:{"bar.text":"Hi"}}, {$unwind:"$bar"}, {$match:{"bar.text":"Hi"}}, {$group:{"_id":"$_id","bars":{$push:"$bar"}}} ],function(err, res) { console.log(res) });});