首页 > 解决方案 > 在MongoDB中按索引获取数组项

问题描述

所以我在 Mongo 集合(v. 4.0.18)中有一个数据结构,看起来像这样......</p>

{
  "_id": ObjectId("242kl4j2lk23423"),
  "name": "Doug",
  "kids": [
    {
      "name": "Alice",
      "age": 15,
    },
    {
      "name": "James",
      "age": 13,
    },
    {
      "name": "Michael",
      "age": 10,
    },
    {
      "name": "Sharon",
      "age": 8,
    }
  ]
}

在 Mongo 中,我如何才能得到只有前两个孩子的这个物体的投影?我希望输出看起来像这样:

{
  "_id": ObjectId("242kl4j2lk23423"),
  "name": "Doug",
  "kids": [
    {
      "name": "Alice",
      "age": 15,
    },
    {
      "name": "James",
      "age": 13,
    }
  ]
}

似乎我应该可以轻松地通过索引获取它们,但我在文档中没有看到任何关于如何做到这一点的内容。我试图解决的现实问题与孩子无关,而且数组可能很长。我正在尝试将其分解并分批处理,而无需将整个内容加载到我的应用程序的内存中。

编辑(非顺序索引):

我注意到,因为我询问了第 1 和第 2 项$slice就足够了……但是,如果我想要第 1 和第 3 项怎么办?有没有办法可以指定要返回的特定数组索引?

关于如何实现这一目标的任何想法或指示?

谢谢!

标签: mongodb

解决方案


如果所需的选择彼此靠近,您正在寻找 $slice 投影运算符。

https://docs.mongodb.com/manual/reference/operator/projection/slice/

这将返回前 2 个

client.db.collection.find({"name":"Doug"}, { "kids": { "$slice": 2 } })

返回

{'_id': ObjectId('5f85f682a45e15af3a907f51'), 'name': 'Doug', 'kids': [{'name': 'Alice', 'age': 15}, {'name': 'James', 'age': 13}]}

这将跳过第一个孩子并返回接下来的两个(第二个和第三个)

client.db.collection.find({"name":"Doug"}, { "kids": { "$slice": [1, 2] } })

返回

{'_id': ObjectId('5f85f682a45e15af3a907f51'), 'name': 'Doug', 'kids': [{'name': 'James', 'age': 13}, {'name': 'Michael', 'age': 10}]}

编辑:

任意选择 1 和 3 可能需要通过聚合管道而不是简单查询进行路由。$match假设您在该字段上有一个索引,性能应该不会有太大的不同。

您的管道步骤应该非常明显,您应该能够从这里获取它。

讨厌指向 RTFM,但这对至少熟悉管道操作非常有帮助。

https://docs.mongodb.com/manual/reference/operator/aggregation/

您的管道应该:

  1. $match 您想要的查询
  2. $set 一些新字段kid_selection到元素 1(第二个元素)和元素 3(第 4 个元素),因为计数从 0 开始。请注意在 Kid_selection 设置器中“kids”键名上的前缀$ 。引用您正在处理的文档中的键时,您需要使用$作为前缀
  3. 投影整个文档,减去我们从中选择的原始孩子字段
client.db.collection.aggregate([
    {"$match":{"name":"Doug"}},
    {"$set": {"kid_selection": [
        { "$arrayElemAt": [ "$kids", 1 ] }, 
        { "$arrayElemAt": [ "$kids", 3 ] }
    ]}},
    { "$project": { "kids": 0 } }
])

返回

{
  '_id': ObjectId('5f86038635649a988cdd2ade'), 
  'name': 'Doug', 
  'kid_selection': [
     {'name': 'James', 'age': 13}, 
     {'name': 'Sharon', 'age': 8}
   ]
}


推荐阅读