如何设计MongoDB结构,使日期查询后返回指定电影场次信息?
解决MongoDB影院场次查询问题
嘿,我来帮你搞定这个影院场次查询的需求~首先得提个关键点:你给的现有文档结构里没有存储场次时间的字段,这可是按时间筛选的核心信息呀!要实现你要的查询,咱们得先把文档结构补全,把影片名称和对应的场次时间都存进去。
完善后的文档结构示例
先给你一个符合查询需求的文档结构参考:
{ "_id" : ObjectId("5abb086677d96df7015c56c6"), "theater" : "Madou", "movies" : [ { "movieName": "Pacific Rim Uprising", "moviePhoto": [ "https://movies.yahoo.com.tw/x/r/w420/i/o/production/movies/March2018/GD9otOLc6d3eprWHC1Ve-2757x4000.jpg", "https://movies.yahoo.com.tw/x/r/w420/i/o/production/movies/March2018/MueV..." ], "showtimes": [ {"time": ISODate("2018-03-27 20:00:00.000Z")}, {"time": ISODate("2018-03-27 21:00:00.000Z")}, {"time": ISODate("2018-03-27 21:40:00.000Z")} ] }, { "movieName": "Tomb Raider", "moviePhoto": [ "https://example.com/tomb-raider-photo1.jpg", "https://example.com/tomb-raider-photo2.jpg" ], "showtimes": [ {"time": ISODate("2018-03-27 19:30:00.000Z")}, {"time": ISODate("2018-03-27 22:00:00.000Z")} ] } ] }
这里把原来的单个movie字段改成了movies数组,每个元素包含影片名、海报和场次时间数组,这样就能精准筛选了。
实现目标查询的两种方案
方案一:用$elemMatch快速筛选(适合简单场景)
如果只是想快速拿到匹配的影片和对应场次,find结合$elemMatch就能搞定,但要注意它的局限:同一份文档里如果有多个匹配的影片,只会返回第一个匹配的对象。
db.theaters.find( { "movies.showtimes.time": { $gte: ISODate("2018-03-27 19:00:00.000Z") }, "movies.movieName": { $in: ["Pacific Rim Uprising", "Tomb Raider"] } }, { "movies": { $elemMatch: { "movieName": { $in: ["Pacific Rim Uprising", "Tomb Raider"] }, "showtimes.time": { $gte: ISODate("2018-03-27 19:00:00.000Z") } } }, "theater": 1 } )
方案二:聚合管道(灵活精准,强烈推荐)
要是想完整拿到所有符合条件的影片和场次,聚合管道是最优解,它能一步步过滤、拆分、重组数据,完全满足你的需求:
db.theaters.aggregate([ // 第一步:先把包含目标影片且有符合时间场次的影院文档捞出来 { $match: { "movies.movieName": { $in: ["Pacific Rim Uprising", "Tomb Raider"] }, "movies.showtimes.time": { $gte: ISODate("2018-03-27 19:00:00.000Z") } } }, // 第二步:把movies数组拆成单个文档,方便后续筛选 { $unwind: "$movies" }, // 第三步:筛选出咱们要的两部影片 { $match: { "movies.movieName": { $in: ["Pacific Rim Uprising", "Tomb Raider"] } } }, // 第四步:把场次数组也拆成单个文档 { $unwind: "$movies.showtimes" }, // 第五步:过滤出时间>=指定时间的场次 { $match: { "movies.showtimes.time": { $gte: ISODate("2018-03-27 19:00:00.000Z") } } }, // 第六步:按影片名称重新分组,把场次整理成数组 { $group: { _id: "$movies.movieName", theater: { $first: "$theater" }, moviePhoto: { $first: "$movies.moviePhoto" }, showtimes: { $push: "$movies.showtimes.time" } } }, // 可选步骤:调整输出格式,把_id换成更直观的movieName { $project: { _id: 0, movieName: "$_id", theater: 1, moviePhoto: 1, showtimes: 1 } } ])
执行这个聚合管道后,你就能得到:
- Pacific Rim Uprising的21:00、21:40场次
- Tomb Raider的19:30场次
完全和你要的结果一致~
内容的提问来源于stack exchange,提问作者Morton
相关产品推荐
相关产品推荐

