使用 Spring 数据在 Mongo 数据库中展开和拆分多个子文档
unwind and split multiple sub document in Mongo DB using Spring Data
这是存储数据的示例
[
{
"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 是 "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 数组=30=]。然后聚合任何给你输出的东西。
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
来获取聚合结果,并使用 return 作为 List<Object>
。如果一切正常,那么您可以将此模型转换为 UserDTO.class
,其结构应与输出相同。
您添加了一个目标集合 users
,这不是一个好的做法。所以使用 mongoTemplate.getCollectionName(YOUR_TARGET_COLLECTION.class)
不是:我没有尝试过这段代码,但这是基于工作 Mongo playground
编写的
这是存储数据的示例
[
{
"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 是 "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 数组=30=]。然后聚合任何给你输出的东西。
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
来获取聚合结果,并使用 return 作为 List<Object>
。如果一切正常,那么您可以将此模型转换为 UserDTO.class
,其结构应与输出相同。
您添加了一个目标集合 users
,这不是一个好的做法。所以使用 mongoTemplate.getCollectionName(YOUR_TARGET_COLLECTION.class)
不是:我没有尝试过这段代码,但这是基于工作 Mongo playground
编写的