如何通过locationId和customerId提取指定客户的预约记录?
MongoDB查询:仅获取指定locationId和customerId的预约记录
场景与问题
给定如下客户预约数据集(顶层包含locationId):
[ { "locationId": 9999, "customerAppointments": [ { "customerId": "1", "appointments": [ { "appointmentId": "cbbce566-da59-42c2-8845-53976ba63d56", "locationName": "Sullivan St" }, { "appointmentId": "5f09e2af-ddae-47aa-9f7c-fd1001a9c5e6", "locationName": "Oak St" } ] }, { "customerId": "2", "appointments": [ { "appointmentId": "964a3c1c-ccec-4082-99e2-65795352ba79", "locationName": "Kellet St" } ] }, { "customerId": "3", "appointments": [] } ] }, { ... }, { ... } ]
需求是通过locationId和customerId提取对应客户的预约记录,期望输出示例:
[ { "appointmentId": "964a3c1c-ccec-4082-99e2-65795352ba79", "locationName": "Kellet St" } ]
尝试了以下查询语句,但返回了包含所有客户记录的完整文档:
db.getCollection("appointments").find( { "locationId" : NumberInt(9999), "customerAppointments" : { "$elemMatch" : { "customerId" : "2" } } });
原因说明
上述查询中的$elemMatch仅用于匹配包含符合条件元素的文档,不会过滤数组中其他不匹配的元素,因此返回的是整个包含目标locationId的文档,而非仅目标客户的预约记录。
解决方案
方法一:使用聚合管道(推荐,支持复杂场景)
通过聚合管道逐步筛选、拆分和提取目标数据:
db.getCollection("appointments").aggregate([ // 1. 筛选出指定locationId的文档 { $match: { locationId: NumberInt(9999) } }, // 2. 拆分customerAppointments数组,每个元素独立成文档 { $unwind: "$customerAppointments" }, // 3. 筛选出指定customerId的客户数据 { $match: { "customerAppointments.customerId": "2" } }, // 4. 将目标appointments数组转为顶层文档(若有多个预约则返回数组) { $replaceRoot: { newRoot: { $first: "$customerAppointments.appointments" } } } ])
如果需要保留预约数组结构(即使只有一条记录),可以调整最后一步:
db.getCollection("appointments").aggregate([ { $match: { locationId: NumberInt(9999) } }, { $unwind: "$customerAppointments" }, { $match: { "customerAppointments.customerId": "2" } }, { $project: { _id: 0, appointments: "$customerAppointments.appointments" } }, { $unwind: "$appointments" }, { $replaceRoot: { newRoot: "$appointments" } } ])
方法二:使用投影(Projection)结合位置操作符
通过查询+投影定位目标元素,再通过map提取最终数据:
db.getCollection("appointments").find( { locationId: NumberInt(9999), "customerAppointments.customerId": "2" }, { _id: 0, "customerAppointments.$.appointments": 1 } ).map(doc => doc.customerAppointments[0].appointments)[0]
这里的$位置操作符会返回数组中第一个匹配customerId的元素,再通过map提取出其中的appointments数组。
内容的提问来源于stack exchange,提问作者ChrisRich
相关产品推荐
相关产品推荐

