【问题标题】:Meteor: Return only single object in nested array within collectionMeteor:仅返回集合内嵌套数组中的单个对象
【发布时间】:2016-08-06 01:48:32
【问题描述】:

我正在尝试使用 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 的引用)并从集合到集合查询数据,或者是否有更强大的方法可以有效地过滤大数据设置为仅包含匹配对象的单个对象,如上所示?

【问题讨论】:

  • Meteor 的客户端实现称为 MiniMongo。它只实现了 MongoDB 选择器的一个子集。

标签: javascript mongodb meteor


【解决方案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,不如创建一个 Meteor 方法,在服务器上调用 Categories.find,并将结果返回给客户端。

【讨论】:

  • 我决定尝试在客户端下划线的_.filter 方法和服务器端的 Meteor 方法之间进行混合,以获得更精细的结果。谢谢!
  • 这是一个非常有帮助的答案!特别是关于需要在服务器上聚合的说明。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-03
  • 1970-01-01
  • 2017-11-17
  • 1970-01-01
  • 2021-09-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多