【问题标题】:Select first element from inner array从内部数组中选择第一个元素
【发布时间】:2017-12-02 18:05:06
【问题描述】:

我想从嵌套数组中选择第一项,而不获取整个文档。

架构/模型

假设我有一个这样的架构:

const parentSchema = mongoose.Schema({
  name: String,
  children: []
});

const grandparentSchema = mongoose.Schema({
  name: String,
  children: [parentSchema]
})

这将转化为这个示例实例:

{
  name: 'Grandparent Foo',
  children: [
    {
      name: 'Parent Foo',
      children: ['Child Foo', 'Child Bar', 'Child Baz']
    }
  ]
}

问题

我想得到'Parent Foo' 的第一个孩子,所以归结为我应该回到'Child Foo'

注意事项

  • 如您所见,孙子是普通的 Strings,而不是 Documents 本身(与父相反),所以我无法使用点符号选择它们。

    李>
  • 我不想返回整个文档并在代码中对其进行过滤。我只想解决第一个孙子数组,因为孙子数组('Parent Foo'children 数组)可能包含数百万个条目。

  • 我需要这个,因为我想$pop 第一个孙子并返回它。为此,我计划先获取项目,然后 $pop 将其关闭,因此我问这个问题

【问题讨论】:

    标签: javascript mongodb mongoose mongodb-query aggregation-framework


    【解决方案1】:

    如果不对数据库投入额外的工作,你真的无法做到。

    作为一般解释:

    Grandparent.find(
      { "children.name": "Parent Foo" },
      { "children.$": 1 }
    )
    

    将仅返回来自 "children" 的匹配条目,并且不存在其他条目。

    如果您明确需要“第一个”数组元素,则使用.aggregate()

    Granparent.aggregate([
      { "$match": { "children.name": "Parent Foo" } },
      { "$addFields": {
        "children": {
          "$map": {
            "input": {
              "$filter": {
                "input": "$children",
                "as": "child",
                "cond": { "$eq": [ "$$child.name", "Parent Foo" ] }
              }
            },
            "as": "child",
            "in": {
              "name": "$$child.name",
              "children": { "$arrayElemAt": [ "$$child.children", 0 ] }
            }
          }
        }
      }}
    ])
    

    因此,您基本上使用$filter 复制标准位置匹配,然后使用$map 使用$arrayElemAt$slice 进行整形以实际获取内部数组的第一个元素。

    相比之下,如果您接受返回“少量额外数据”,那么您只需切断位置匹配:

    Grandparent.find(
      { "children.name": "Parent Foo" },
      { "children.$": 1 }
    ).lean().exec((err,docs) => {
      docs = docs.map( doc => {
        doc.children = doc.children.map( c => c.children = c.children.slice(0,1) );
        return doc;
      });
      // do something with docs
    

    所以我们在光标中返回了更多内容,并以最小的努力摆脱了那一点点数据。

    由于实际数据的实际大小,里程可能会有所不同,但如果差异“小”,那么通常最好在客户端而不是服务器中“修剪”。

    【讨论】:

    • Grand - 很抱歉没有用 mongoose 标记这个。我猜这是一个标准的mongo驱动程序答案,因此db.collection.find而不是Grandparent.find(),对吗?我想试驾你在这里给我的解决方案,但我不确定它是同一个环境。
    • @NicholasKyriakides 是的。实际上,我经常会删除这样的标签,因为无论如何问题中绝对没有猫鼬“特定”。使用型号名称,但其他一切都保持不变。当然,除了使用回调或承诺。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-14
    • 1970-01-01
    • 2014-07-23
    • 2015-02-25
    • 1970-01-01
    相关资源
    最近更新 更多