查找后填充mongoose
我有一些麻烦查询文件后通过mongoose匹配的文件内匹配的值。
我的模式是这样的:
var EmailSchema = new mongoose.Schema({ type: String }); var UserSchema = new mongoose.Schema({ name: String, email: [{type:Schema.Types.ObjectId, ref:'Email'}] });
例如,我希望让所有拥有types=“Gmail”的电子邮件的用户都可以使用。
以下查询返回空结果:
Users.find({'email.type':'Gmail').populate('email').exec( function(err, users) { res.json(users); });
我不得不求助于像这样在JS中过滤结果:
users = users.filter(function(user) { for (var index = 0; index < user.email.length; index++) { var email = user.email[index]; if(email.type === "Gmail") { return true; } } return false; });
有没有办法从mongoose直接查询这样的东西?
@Jason Cust已经很好的解释了这一点 – 在这种情况下,最好的解决scheme是改变模式,以防止通过存储在单独集合中的文档的属性来查询Users
。
这是我能想到的最好的解决scheme,不会强迫你这么做(因为你在评论中说你不能这样做)。
Users.find().populate({ path: 'email', match: { type: 'Gmail' } }).exec(function(err, users) { users = users.filter(function(user) { return user.email; // return only users with email matching 'type: "Gmail"' query }); });
我们在这里做的只是填充匹配附加查询( match
选项在.populate()
调用)的email
– 否则Users
文档中的email
字段将被设置为null
。
剩下的就是在返回的users
数组上进行.filter
,就像在你原来的问题中一样 – 只用简单的非常通用的检查。 正如你所看到的 – 无论是在那里的email
或不是。
Mongoose的populate
函数不会直接在Mongo中执行。 相反,在初始find
查询返回一个集合文档之后, populate
会在被引用的集合上创build一个单独的查询查询的数组来执行,然后将结果合并回原始文档。 所以基本上你的find
查询试图使用被引用文档的属性(尚未被提取,因此是undefined
)来过滤原始结果集。
在这个用例中,将电子邮件存储为子文档数组而不是单独的集合来实现您想要执行的操作似乎更为合适。 另外,作为一般的文档存储devise模式,这是将数组作为子文档存储是有意义的用例之一:有限的大小和很less的修改。
将模式更新为:
var EmailSchema = new mongoose.Schema({ type: String }); var UserSchema = new mongoose.Schema({ name: String, email: [EmailSchema] });
然后下面的查询应该工作:
Users.find({'email.type':'Gmail').exec(function(err, users) { res.json(users); });