我尝试使用Meteor find().fetch()
过滤返回的数据集只包含一个对象,如果我查询单个子文档但它不会显得非常有用我收到了几个,有些甚至不包含任何匹配的术语。
我有一个简单的混合数据集合,如下所示:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"name" : "Entertainment",
"items" : [
{
"_id" : ObjectId("57a38b5f2bd9ac8225caff06"),
"slug" : "this-is-a-long-slug",
"title" : "This is a title"
},
{
"_id" : ObjectId("57a38b835ac9e2efc0fa09c6"),
"slug" : "mc",
"title" : "Technology"
}
]
}
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e8"),
"name" : "Sitewide",
"items" : [
{
"_id" : ObjectId("57a38bc75ac9e2efc0fa09c9"),
"slug" : "example",
"name" : "Single Example"
}
]
}
我可以使用MongoDB shell轻松查询嵌套items
数组中的特定对象:
db.categories.find( { "items.slug": "mc" }, { "items.$": 1 } );
这会返回好的数据,它只包含我想要使用的单个对象:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"items" : [
{
"_id" : ObjectId("57a38b985ac9e2efc0fa09c8")
"slug" : "mc",
"name" : "Single Example"
}
]
}
但是,如果直接尝试Meteor中的类似查询:
/* server/publications.js */
Meteor.publish('categories.all', function () {
return Categories.find({}, { sort: { position: 1 } });
});
/* imports/ui/page.js */
Template.page.onCreated(function () {
this.subscribe('categories.all');
});
Template.page.helpers({
items: function () {
var item = Categories.find(
{ "items.slug": "mc" },
{ "items.$": 1 } )
.fetch();
console.log('item: %o', item);
}
});
结果并不理想,因为它返回整个匹配的块,以及嵌套的items
数组中的每个对象:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"name" : "Entertainment",
"boards" : [
{
"_id" : ObjectId("57a38b5f2bd9ac8225caff06")
"slug" : "this-is-a-long-slug",
"name" : "This is a title"
},
{
"_id" : ObjectId("57a38b835ac9e2efc0fa09c6")
"slug" : "mc",
"name" : "Technology"
}
]
}
我当然可以使用for循环进一步过滤返回的游标以获得所需的对象,但是在处理更大的数据集时,这似乎是不可扩展的,而且非常低效。
我无法理解为什么Meteor的find
会返回一组与MongoDB的shell find
完全不同的数据,唯一合理的解释是两个函数签名都是不同。
我是否应该将嵌套集合拆分为较小的集合并采用更多关系数据库方法(即存储对ObjectID的引用)和从集合到集合中查询数据,或者是否有更强大的方法可以有效地过滤大数据设置为仅包含匹配对象的单个对象,如上所示?
答案 0 :(得分:1)
Meteor使用的Mongo的客户端实现称为minimongo。它目前仅实现可用Mongo功能的子集。 Minimongo目前不支持基于预测的预测。来自Meteor API的Field Specifiers部分:
$和$ elemMatch等字段运算符尚未在客户端提供。
这是您在客户端和Mongo shell之间获得不同结果的原因之一。通过将"items.$"
更改为"items"
,您可以获得与原始查询最接近的结果:
Categories.find(
{ "items.slug": "mc" },
{ "items": 1 }
).fetch();
但是这个查询仍然不太正确。 Minimongo希望您的第二个find
参数成为docs中列出的允许选项参数之一。例如,要过滤fields
,您必须执行以下操作:
Categories.find(
{ "items.slug": "mc" },
{
fields: {
"items": 1
}
}
).fetch();
在客户端(使用Minimongo),您需要自己进一步过滤结果。
还有另一种方法可以做到这一点。如果在服务器上运行Mongo查询,则不会使用Minimongo,这意味着支持投影。作为一个简单的例子,请尝试以下方法:
<强> /server/main.js 强>
const filteredCategories = Categories.find(
{ "items.slug": "mc" },
{
fields: {
"items.$": 1
}
}
).fetch();
console.log(filteredCategories);
投影将起作用,记录的结果将与您直接使用Mongo控制台时看到的结果相匹配。您可以改为在客户端运行Categories.find
,而不是在服务器上调用Categories.find
,并将结果返回给客户端。