mongodb - 使用 Spring Data 在 Mongo DB 中展开和拆分多个子文档
问题描述
这是存储数据的示例
[
{
"userId":"user123",
"name":"John",
"card":{
"amount":1000.0,
"sentMoneyList":[
{
"creationDate":"2019-08-07T00:00:00.000+0000",
"shopId":"merchant1",
"loyaltyPoint":200,
"amount":250
},
{
"creationDate":"2019-01-07T00:00:00.000+0000",
"shopId":"merchant2",
"loyaltyPoint":100,
"amount":99
}
],
"receivedMoneyList":[
{
"creationDate":"2019-09-07T00:00:00.000+0000",
"amount":40
},
{
"creationDate":"2019-03-07T00:00:00.000+0000",
"amount":500
}
]
}
}
]
我想建立一个从给定日期开始的所有用户收到和发送资金的时间表。在 startDate is 的情况下"2019-02-01T00:00:00.000+0000"
,我的请求的输出应该是这样的:
[
{
"userId":"user123",
"name":"John",
"card":{
"amount":1000.0,
"sentMoneyList":[
{
"creationDate":"2019-08-07T00:00:00.000+0000",
"shopId":"merchant1",
"loyaltyPoint":200,
"amount":250
}
]
}
},
{
"userId":"user123",
"name":"John",
"card":{
"amount":1000.0,
"receivedMoneyList":[
{
"creationDate":"2019-09-07T00:00:00.000+0000",
"amount":40
}
]
}
},
{
"userId":"user123",
"name":"John",
"card":{
"amount":1000.0,
"receivedMoneyList":[
{
"creationDate":"2019-03-07T00:00:00.000+0000",
"amount":500
}
]
}
}
]
这里是试图得到这个结果的java代码:
Criteria criteriaClient = new Criteria();
MatchOperation matchOperation = match(criteriaClient.orOperator(
Criteria.where("card.sentMoneyList.creationDate").gte(startDate),
Criteria.where("card.receivedMoneyList.creationDate").gte(startDate)));
UnwindOperation unwindSent = Aggregation.unwind("card.sentMoneyList");
UnwindOperation unwindReceived = Aggregation.unwind("card.receivedMoneyList");
Aggregation aggregation = Aggregation.newAggregation(unwindSent, unwindReceived, matchOperation);
List<UserDTO> result = mongoTemplate.aggregate(
aggregation, "users", UserDTO.class).getMappedResults();
它给出了一个空列表。为了得到上面的结果,查询中缺少什么?谢谢
解决方案
您可以实现预期的输出,$facet
从而帮助您对传入数据进行分类。在这里,我在 sentMoney 数组中获得了sentMoneyList数组,在receivedMoney中获得了 receivedMoneyList数组。然后聚合任何给你输出的东西。
public List<Object> test() {
Aggregation aggregation = Aggregation.newAggregation(
facet(
p -> new Document("$project",
new Document("card.receivedMoneyList", 0)
),
a -> new Document("$addFields",
new Document("card.sentMoneyList",
new Document("$filter",
new Document("input", "$card.sentMoneyList")
.append("cond",
new Document("$gte", Arrays.asList("$$this.creationDate", "2019-02-01T00:00:00.000+0000"))
)
)
)
),
unwind("$card.sentMoneyList")
).as("sentMoney").and(
p -> new Document("$project",
new Document("card.sentMoneyList", 0)
),
a -> new Document("$addFields",
new Document("card.receivedMoney",
new Document("$filter",
new Document("input", "$card.receivedMoney")
.append("cond",
new Document("$gte", Arrays.asList("$$this.creationDate", "2019-02-01T00:00:00.000+0000"))
)
)
)
),
unwind("$card.receivedMoney")
).as("receivedMoney"),
p -> new Document("$project",
new Document("combined",
new Document("$concatArrays", Arrays.asList("$sentMoney", "$receivedMoney"))
)
),
unwind("$combined"),
replaceRoot("combined")
).withOptions(AggregationOptions.builder().allowDiskUse(Boolean.TRUE).build());
return mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(Users.class), Object.class).getMappedResults();
}
首先,我请求您使用Object.class
来获取聚合结果并以List<Object>
. 如果效果很好,那么您可以将此模型转换UserDTO.class
为与输出结构相同的模型。
您添加了一个目标集合users
,这不是一个好习惯。所以使用mongoTemplate.getCollectionName(YOUR_TARGET_COLLECTION.class)
不是:我没有尝试过这段代码,但这是基于工作的Mongo 游乐场编写的
推荐阅读
- ios - 使用 Cordova 的 Ionic 应用程序在 iOS 模拟器中工作但不在真实设备上
- android - 如何从 exoplayer 中删除搜索栏
- ios - CLFloor 返回级别 2146959360?
- database-design - BigQuery 表设计最佳实践:日期分区和分片的组合?
- pip - fbprophet 无限安装
- php - 在 WooCommerce 的购物车和结帐页面显示每件商品的总重量
- opencv - FAST 检测器最初是如何找到候选边缘的?任何边缘和特征检测器最初是如何找到候选者的?
- c# - 我需要使用什么 IP 来使用 C# 中的套接字通过 LAN 进行通信?
- installation - (Windows)安装程序如何包含文件?
- python - 如何在 Tkinter 中动态创建没有特定类实例化的小部件?