MongoDB - 查询嵌入式文档数组

时间:2021-05-18 16:36:40

标签: database mongodb

我最近开始使用MongoDB来保存一个项目的数据,基本思路如下。

在服务器端,我在 WebSocket 上接收一些 JSON 对象并将其存储在数据库中。

我收到的数据如下所示:

{ 
    {ident: "message_1"},
    data:
    [
        {id: "data_1", value : 10},
        {id: "data_2", value : 20},
        {id: "data_3", value : 40},
        {id: "data_4", value : 60},
        {id: "data_4", value : 60},
    ], 
    timestamp : 12234456
}

我目前正在数据库中保存整个 JSON 对象。

服务器还应该处理用户 http 请求,它在数据库中查询请求的数据。用户请求总是针对 data 数组的一个元素和时间戳。因此,服务器响应应如下所示:

{ id: "data_1", value : 10, timestamp : 12234456}

我尝试将 db.collection.find$elemMatch 一起使用,但我的输出仍然包含 data 数组和所需的元素。

{
    data: 
    [{
        id: "data_1",
        value: 10
    }],
   timestamp : 12234456
}

所以我的问题是是否有可能查询数据库并仅返回“data”数组的所需元素以及时间戳,否则我需要在读取数据库后重新创建响应 JSON 对象。

亲切的问候。

2 个答案:

答案 0 :(得分:2)

欢迎来到蒙戈世界。您可以通过聚合轻松实现这一点

  • $uwnind 解构数组
  • $match 获取期望值
  • $addFields 向对象添加新字段
  • $replaceRoot 使对象成为根

这是代码

db.collection.aggregate([
  { "$unwind": "$data" },
  { "$match": { "data.id": "data_1" } },
  { "$addFields": { "data.timestamp": "$timestamp" } },
  { "$replaceRoot": { "newRoot": "$data" } }
])

工作Mongo playground

答案 1 :(得分:0)

虽然@varman 的回答对这个问题是正确的,但为了更好地匹配我的情况,数组 data 将有很多元素(超过 100),因为@varman 在评论“unwind”中可能特别昂贵当数组包含大量元素时。因此,理想情况下,当数组仅包含所需元素时,我更愿意执行“展开”,以实现我将订单更改为以下内容:

  • 使用 "$match 仅获取具有所需 data 元素的文档
{ "$match": { "data.id": "data_1" } }
  • 使用 $project$filter 从数据中过滤掉不需要的元素
   $project: {
      data: {
        $filter: {
          input: "$data",
          as: "data",
          cond: {$eq: ["$$data.id", "data_1"]}
        }
      },
      "timestamp": 1,
      "_id": 0
    }
  • 现在添加正确答案中的 timestamp 字段
  { $addFields: {"data.timestamp": "$timestamp"} }
  • 使用unwind从输入文档中解构data数组字段,为每个元素输出一个文档。
  {
    $unwind: "$data"
  }
  • 然后使用 $replaceRoot 将输入文档替换为 data 字段。
{"$replaceRoot": {"newRoot": "$data"}} 

希望这对需要做同样事情的任何人都有用,如果您对我当前的设置有任何建议/改进,请我来寻求建议,因为我是 MongoDB 的新手。

运行示例 Mongo Playground