MongoDB查询内嵌数组(限定返回符合条件的数组中的数据)(1)

本文介绍在MongoDB中如何精确查询内嵌数组中的特定元素,包括使用$elemMatch和聚合管道等高级查询方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目背景

最近在项目中使用mongdb来保存压测结果中的监控数据,那么在获取监控数据时,遇到这样一个问题: 一个doucument中包含一个内嵌数组,其中内嵌数组也是分成好几类的数组(可以通过标识判断),那么我只需要返回特定的数组,而不是返回内嵌数组的所有数据。
原始数据:

{
    "_id" : ObjectId("5aab3460353df3bd352e0e15"),
    "addTime" : ISODate("2018-03-16T03:05:04.363Z"),
    "tag" : "test",
    "userInfo" : [ 
        {
            "name" : "cj",
            "address" : "江苏",
            "age" : 24.0,
            "userTag" : "stu"
        }, 
        {
            "name" : "hj",
            "address" : "江苏",
            "age" : 26.0,
            "userTag" : "stu"
        }, 
        {
            "name" : "lbl",
            "address" : "美国",
            "age" : 22.0,
            "userTag" : "teach"
        }
    ]
}

查询条件是 tag =“test” userTag=”teach” 的学生的信息。期望返回的结果如下所示:

{
    "_id" : ObjectId("5aab3460353df3bd352e0e15"),
    "userInfo" : [ 
        {
            "name" : "lbl",
            "address" : "美国",
            "age" : 22.0,
            "userTag" : "teach"
        }
    ]
}

但大多是find 的结果 是这样的

db.test.find({"userInfo.userTag":"teach","tag":"test"})
{
    "_id" : ObjectId("5aab3460353df3bd352e0e15"),
    "addTime" : ISODate("2018-03-16T03:05:04.363Z"),
    "tag" : "test",
    "userInfo" : [ 
        {
            "name" : "cj",
            "address" : "江苏",
            "age" : 24.0,
            "userTag" : "stu"
        }, 
        {
            "name" : "hj",
            "address" : "江苏",
            "age" : 26.0,
            "userTag" : "stu"
        }, 
        {
            "name" : "lbl",
            "address" : "美国",
            "age" : 22.0,
            "userTag" : "teach"
        }
    ]
}

$elemMatch 介绍

其实我们在学习一个新的东西的时候,我建议是去官方文档查看一下,毕竟官方的才是最权威的。官方地址:
https://docs.mongodb.com/manual/reference/operator/projection/elemMatch/#proj._S_elemMatch.
我们可以看到 $elemMatch 是在projections方法下面,projections代表是限制返回字段的方法。
修改后的方法:

db.test.find({"userInfo.userTag":"teach","tag":"test"},{"userInfo":{$elemMatch{"userTag":"teach"}}})

执行结果

{
    "_id" : ObjectId("5aab3460353df3bd352e0e15"),
    "userInfo" : [ 
        {
            "name" : "lbl",
            "address" : "美国",
            "age" : 22.0,
            "userTag" : "teach"
        }
    ]
}

终于得到我想要的结果了 hhhhhhhhhhhhhhhhhhhhh。
然后我又想获取userInfo.userTag = “stu” 的数据,很简单啊

db.test.find({"userInfo.userTag":"teach","tag":"test"},{"userInfo":{$elemMatch:{"userTag":"stu"}}})

但是结果出人意料:

{
    "_id" : ObjectId("5aab3460353df3bd352e0e15"),
    "userInfo" : [ 
        {
            "name" : "cj",
            "address" : "江苏",
            "age" : 24.0,
            "userTag" : "stu"
        }
    ]
}

明明是2条stu的结果,为什么至返回一条呢? 其实$elemMatch 的定义 在官网中已经说过了,这是原话:

The $elemMatch operator limits the contents of an <array> field from the query results to contain only the first element matching the $elemMatch condition.

注意 only the first element 也就是仅仅匹配第一个合适的元素。
那么 对于数组中只有一个返回元素,我们可以使用$elemMatch来查询,但是对于多个元素$elemMatch 是不适应。

$Aggregation介绍

文档地址:https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/

  1. $unwind:
    https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/#pipe._S_unwind
    大概意思就是将数组中的每一个元素转为每一条文档

  2. $match:
    https://docs.mongodb.com/manual/reference/operator/aggregation/match/
    简单的过滤文档,条件查询。

  3. $project
    https://docs.mongodb.com/manual/reference/operator/aggregation/project/
    修改输入文档的结构

执行命令:

db.test.aggregate([{"$unwind":"$userInfo"},
{"$match":{"userInfo.userTag":"stu","tag":"test"}},
{"$project":{"userInfo":1}}])

结果

/* 1 */
{
    "_id" : ObjectId("5aab3460353df3bd352e0e15"),
    "userInfo" : {
        "name" : "cj",
        "address" : "江苏",
        "age" : 24.0,
        "userTag" : "stu"
    }
}

/* 2 */
{
    "_id" : ObjectId("5aab3460353df3bd352e0e15"),
    "userInfo" : {
        "name" : "hj",
        "address" : "江苏",
        "age" : 26.0,
        "userTag" : "stu"
    }
}

这样的一个结果就是我们想要的。感兴趣的同学可以分别执行下这个三个操作(比较看看三个结果有什么不同),你就能理解 $unwind、$match、$project 三个方法的作用

db.test.aggregate([{"$unwind":"$userInfo"}])
db.test.aggregate([{"$unwind":"$userInfo"},{"$match":{"userInfo.userTag":"stu","tag":"test"}}])
db.test.aggregate([{"$unwind":"$userInfo"},{"$match":{"userInfo.userTag":"stu","tag":"test"}},{"$project":{"userInfo":1}}])

总结

  1. 之前查询内嵌数组时,采用的方法是将整条document查询出来之后,在对内嵌数组进行代码过滤。只是觉得这种查询方式并没有用到mongodb的其他的一些方法,还是需求驱动学习。
  2. 学习一个新的东西建议从官方文档开始学习。

结束语:

下一篇开始介绍在spring中如何查询mongdb。

### 使用 JavaScript 查询 MongoDB 并仅返回匹配的数组元素 为了实现只返回满足条件的嵌入式数组元素,在查询时应利用 `$elemMatch` 投影选项来筛选特定字段中的条目[^1]。 当执行这样的操作时,假设有一个名为 `users` 的集合,其中包含具有 `finished` 数组属性的文档。如果目标是从这些文档中检索那些其 `finished` 数组内存在至少一个介于 15 和 20 之间的数值,则可以通过如下方式构建查询: ```javascript db.users.find( {}, { "finished.$": 1, _id: 0 } ).toArray(function(err, docs) { console.log(docs); }); ``` 然而,上述例子适用于单个匹配项的情况;对于多个可能符合条件的情形,应当采用更精确的方式——即通过聚合管道使用 `$filter` 表达式来进行处理[^3]。 下面是一个完整的函数示例,展示了如何连接到 MongoDB Atlas 数据库并应用过滤逻辑以获取指定范围内的成绩记录: ```javascript exports = function() { const mongodb = context.services.get("mongodb-atlas"); const usersCollection = mongodb.db("yourDatabase").collection("users"); usersCollection.aggregate([ { $project: { filteredFinished: { $filter: { input: "$finished", as: "item", cond: { $and: [{ $gt: ["$$item", 15]}, {$lt: ["$$item", 20]}]} } }, _id: 0 } } ]).toArray((err, result) => { if (err) throw err; console.log(result); }); }; ``` 此代码片段定义了一个导出函数,该函数会访问存储服务实例下的 `users` 集合,并运用聚合框架中的 `$filter` 来限定输出结果仅为 `finished` 数组里大于 15 小于 20 的成员[^2]。
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值