Javascript Meteor:仅返回集合中嵌套数组中的单个对象

Javascript Meteor:仅返回集合中嵌套数组中的单个对象,javascript,mongodb,meteor,Javascript,Mongodb,Meteor,我正在尝试使用Meteor的find().fetch()过滤返回的数据集。为了只包含一个对象,如果我查询单个子文档,它似乎没有多大用处,但我会收到几个,有些甚至不包含任何匹配的项 我有一个简单的混合数据收集,如下所示: { "_id" : ObjectId("570d20de3ae6b49a54ee01e7"), "name" : "Entertainment", "items" : [ { "_id" : ObjectId("57

我正在尝试使用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在嵌套的
数组中轻松查询特定对象,如下所示:

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);
     }
 });
结果并不理想,因为它返回整个匹配的块,以及嵌套的
数组中的每个对象:

{
    "_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的引用)和从一个集合到另一个集合查询数据,或者,是否有更强大的方法可以有效地将大型数据集过滤为仅包含上述匹配对象的单个对象?

Meteor使用的Mongo客户端实现称为。它目前只实现了可用Mongo功能的一个子集。Minimongo目前不支持基于美元的预测。来自Meteor API的部分:

客户端尚未提供$elemMatch和$elemMatch等现场操作员

这就是为什么在客户端和Mongo shell之间得到不同结果的原因之一。使用原始查询可以得到的最接近的结果是通过将
“items.$”
更改为
“items”

不过,这个问题仍然不太正确。Minimongo希望您的第二个
find
参数是中列出的允许选项参数之一。例如,要过滤
字段
,您必须执行以下操作:

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控制台时看到的结果相匹配。您可以创建一个Meteor方法,在服务器上调用您的
类别。查找,并将结果返回给客户端。Meteor的客户端实现称为MiniMongo。它只实现MongoDB选择器的一个子集。我决定尝试在客户端的下划线的
..filter
方法和服务器端的Meteor方法之间进行混合,以获得更精确的结果。谢谢这是一个非常有用的答案!特别是关于需要在服务器上聚合的说明。谢谢
const filteredCategories = Categories.find(
  { "items.slug": "mc" },
  {
    fields: {
      "items.$": 1
    }
  }
).fetch();
console.log(filteredCategories);