当前位置:网站首页>MongoDB分组取每组中一条数据
MongoDB分组取每组中一条数据
2022-07-23 15:05:00 【pilaf1990】
需求背景
有一个mongo collection,里面存放了运送货物的司机位置信息,字段主要有
_id: mongodb默认的主键字段
orderId:订单id
positionTime:位置上报时的时间戳
lon:经度信息
lat:纬度信息
现在需要支持根据一批订单id,查询它们最新位置的经纬度。
需求分析
根据需求背景,可以知道,查询的条件是按照订单id作为分组,每个分组内按照positionTime降序排序,然后将分组内的第一条记录的所有字段返回即可。
在NoSQL Booster中查询的语句:
// _id被覆盖的查询方式
db.position_collection
.aggregate([
{
// 过滤出符合条件的记录,这里用订单id列表
$match: { orderId: {$in: [26556031845626880,26550496434145792]}}},
// 按照订单id升序,定位时间降序排序
{$sort: { orderId: 1, positionTime:-1}},
{$group:{
// 根据orderId字段分组,mongodb要求必须得用_id来表示分组的字段,但是这样查询出来的document中的_id字段就变成了orderId了
_id:"$orderId",
// 如果想把表本身的_id字段返回怎么办?可以加一行 _id:{$first: "$_id"}么?答案是不可以,mongodb会报错
//返回分组内的第一条记录的orderId
orderId:{$first: "$orderId"},
//返回分组内的第一条记录的positionTime
positionTime:{$first: "$positionTime"}
}
}
])
// limit后面应该用订单数量做个限制
.limit(10)
// _id不会被覆盖的查询方式
db.position_collection
.aggregate([
{$match: { orderId: {$in: [26556031845626880,26550496434145792]}}},
{$sort: { orderId: 1, positionTime:-1}},
{$group:{
_id:"$orderId",
// 通过$$ROOT拿到原来记录的信息,存到doc中
doc:{$first: "$$ROOT"},
}},
// 从doc中还原出原来记录的信息,也包括最原始的_id
{$replaceRoot: { newRoot: "$doc" }}
])
.limit(10)
Java Demo代码
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.model.Accumulators;
import com.mongodb.client.model.Aggregates;
import com.mongodb.client.model.Filters;
import org.bson.BsonDocument;
import org.bson.BsonDocumentWriter;
import org.bson.Document;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class MongoDemo {
private void queryLatestPosition(String collectionName,List<Long> orderIds) {
// 因为group后面需要根据orderId分组,取定位时间最大的那条记录,group后面要求用_id来表示分组字段,但是这会存在一个问题,
// mongodb查出来的document中原来的_id字段会被设置为一个document,如果想把原来的_id字段也拿出来,就要用replaceRoot
// 但是我们公司的mongo maven依赖中用到的mongo-java-driver-3.2.2版本的Aggregates中没有replaceRoot方法可用,于是就
// 模仿Aggregates.group方法中的操作来自己搞一个。
// 关于replaceRoot解决的问题,可以参考https://stackoverflow.com/questions/52566913/how-to-group-in-mongodb-and-return-all-fields-in-result/52578475
BsonDocumentWriter bsonDocumentWriter = new BsonDocumentWriter(new BsonDocument());
bsonDocumentWriter.writeStartDocument();
bsonDocumentWriter.writeStartDocument("$replaceRoot");
bsonDocumentWriter.writeString("newRoot","$doc");
bsonDocumentWriter.writeEndDocument();
bsonDocumentWriter.writeEndDocument();
BsonDocument replaceRoot = bsonDocumentWriter.getDocument();
AggregateIterable<Document> aggregateIterable = myMongoClient.getCollection(collectionName)
.aggregate(Arrays.asList(
// 按照orderId列表过滤记录
Aggregates.match(Filters.in("orderId",orderIds)),
// 按照orderId升序、positionTime降序 排序
Aggregates.sort(new Document().append("orderId",1).append("positionTime",-1)),
// 根据orderId分组
Aggregates.group(
new Document("_id", "$orderId"),
Arrays.asList(
// 取分组第一条数据,即positionTime最大的那条,放到doc字段里,供后续的replaceRoot替换用
Accumulators.first("doc","$$ROOT"))
),
// 如果你的API中有Aggregates.replaceRoot,直接使用就可以了
replaceRoot,
Aggregates.limit(orderIds.size())
))
//设置超时时间
.maxTime(4000, TimeUnit.MILLISECONDS);
for (Document document : aggregateIterable) {
// 遍历document进行处理
}
}
}
参考资料:
1.https://stackoverflow.com/questions/52566913/how-to-group-in-mongodb-and-return-all-fields-in-result/52578475
边栏推荐
- 12 pictures +6k figure ZGC garbage collector and tuning skills
- 【flask高级】从源码深入理解flask路由之endpoint
- @Bean 注解的方法调用多次会创建多个bean 实例吗
- Unity production QR code scanning
- Element content must consist of character data or tags with correct format
- Why do you get confused when you ask JVM???
- In depth understanding of USB communication protocol
- nVisual综合布线管理软件与网管软件的区别
- @Will multiple bean instances be created by multiple method calls of bean annotations
- Tapdata 与优炫数据库完成产品兼容性互认证
猜你喜欢
![[flask advanced] deeply understand the endpoint of flask routing from the source code](/img/b9/b8dd5bb8aaa1fa5580a7048b2d6ef1.png)
[flask advanced] deeply understand the endpoint of flask routing from the source code

面试官:MySQL 数据库查询慢,除了索引问题还可能是什么原因?

活动报名:如何零基础快速上手开源的 Tapdata Live Data Platform?

程序员最想干的三件事 |漫画

Don't ask me again why MySQL hasn't left the index? For these reasons, I'll tell you all

nVisual综合布线管理软件与网管软件的区别

KV260单板PS控制设置IIC开关芯片

xlinx pcie xvc

Solutions to sap Hana database backup failure

SAP HANA数据库备份失败解决办法
随机推荐
Redis数据丢失问题
从马尔可夫链到GPT,字节跳动AI Lab总监李航细说语言模型的前世今生
Tapdata 与优炫数据库完成产品兼容性互认证
工業物聯網中的時序數據
@Will multiple bean instances be created by multiple method calls of bean annotations
TYPE-C 转OTG(USB2.0传输数据)+PD充电协议芯片 乐得瑞LDR6028/LDR6023SS
sns_ sensor_ instance_ api
Redis分布式锁,没它真不行
网页基础模版
[introduction series of redis] redis builds master-slave servers
基于OpenPGP的文件管理系统
日期格式化
el-input使用
Redis distributed lock, it's really impossible without it
Makefile common functions notdir, wildcard, patsubst
工业物联网中的时序数据
网页返回更新
单细胞论文记录(part19)--A comprehensive comparison on cell-type composition inference for ST data
几何参数化重构
[pytorch] basic use 7. GPU allocation