我在 MongoDB shell 中完成了以下聚合,以获取每个用户每种类型的警报数量:
db.getCollection('alerts').aggregate(
{
$unwind:"$son"
},
{
$group:
{
_id:{
son: "$son",
level: "$level"
},
count: { $sum: 1 }
}
},
{
$group:
{
_id:{
son: "$_id.son"
},
alerts: { $addToSet: {
level: "$_id.level",
count: "$count"
}}
}
}
)
我已将其转换为 Spring Data MongoDB,如下所示:
TypedAggregation<AlertEntity> alertsAggregation =
Aggregation.newAggregation(AlertEntity.class,
unwind("$son"),
Aggregation.group("$son", "$level").count().as("count"),
Aggregation.group("$_id.son")
.addToSet(new BasicDBObject("level", "$_id.level").append("count", "$count")).as("alerts"));
// Aggregation.match(Criteria.where("_id").in(sonIds)
AggregationResults<AlertsBySonDTO> results = mongoTemplate.
aggregate(alertsAggregation, AlertsBySonDTO.class);
List<AlertsBySonDTO> alertsBySonResultsList = results.getMappedResults();
return alertsBySonResultsList;
我不清楚并且无法让它工作,是投影标识符,如果可能的话,投影用户的名称(son变量)。
The resulting DTO is as follows
public final class AlertsBySonDTO implements Serializable {
private static final long serialVersionUID = 1L;
@JsonProperty("identity")
private String id;
@JsonProperty("alerts")
private ArrayList<Map<String, String>> alerts;
}
但在 id 属性中包含整个嵌入的子实体。
这是警报集合的结构。
JSON 警报格式:
{
"_id" : ObjectId("59e6ff3d9ef9d46a91112890"),
"_class" : "es.bisite.usal.bulltect.persistence.entity.AlertEntity",
"level" : "INFO",
"title" : "Alerta de Prueba",
"payload" : "Alerta de Prueba",
"create_at" : ISODate("2017-10-18T07:13:45.091Z"),
"delivery_mode" : "PUSH_NOTIFICATION",
"delivered" : false,
"parent" : {
"$ref" : "parents",
"$id" : ObjectId("59e6ff369ef9d46a91112878")
},
"son" : {
"$ref" : "children",
"$id" : ObjectId("59e6ff389ef9d46a9111287b")
}
}
/* 2 */
{
"_id" : ObjectId("59e6ff6d9ef9d46a91112892"),
"_class" : "es.bisite.usal.bulltect.persistence.entity.AlertEntity",
"level" : "WARNING",
"title" : "Token de acceso inv�lido.",
"payload" : "El token de acceso YOUTUBE no es v�lido",
"create_at" : ISODate("2017-10-18T07:14:53.449Z"),
"delivery_mode" : "PUSH_NOTIFICATION",
"delivered" : false,
"parent" : {
"$ref" : "parents",
"$id" : ObjectId("59e6ff369ef9d46a91112878")
},
"son" : {
"$ref" : "children",
"$id" : ObjectId("59e6ff389ef9d46a9111287b")
}
}
/* 3 */
{
"_id" : ObjectId("59e6ff6d9ef9d46a91112893"),
"_class" : "es.bisite.usal.bulltect.persistence.entity.AlertEntity",
"level" : "WARNING",
"title" : "Token de acceso inv�lido.",
"payload" : "El token de acceso INSTAGRAM no es v�lido",
"create_at" : ISODate("2017-10-18T07:14:53.468Z"),
"delivery_mode" : "PUSH_NOTIFICATION",
"delivered" : false,
"parent" : {
"$ref" : "parents",
"$id" : ObjectId("59e6ff369ef9d46a91112878")
},
"son" : {
"$ref" : "children",
"$id" : ObjectId("59e6ff389ef9d46a9111287c")
}
}
有人知道我该如何解决这个问题吗?
提前致谢
最佳答案
<强>1。使用 MongoDB 版本 3.4
这些是我为重现您的用例而创建的以下集合:
警报集合
{
"_id" : ObjectId("59e6ff3d9ef9d46a91112890"),
"_class" : "es.bisite.usal.bulltect.persistence.entity.AlertEntity",
"level" : "INFO",
"title" : "Alerta de Prueba",
"payload" : "Alerta de Prueba",
"create_at" : ISODate("2017-10-18T07:13:45.091+0000"),
"delivery_mode" : "PUSH_NOTIFICATION",
"delivered" : false,
"parent" : DBRef("parents", ObjectId("59e6ff369ef9d46a91112878")),
"son" : DBRef("children", ObjectId("59e72ff0572ae72d8c063666"))
}
{
"_id" : ObjectId("59e6ff6d9ef9d46a91112892"),
"_class" : "es.bisite.usal.bulltect.persistence.entity.AlertEntity",
"level" : "WARNING",
"title" : "Token de acceso inv�lido.",
"payload" : "El token de acceso YOUTUBE no es valido",
"create_at" : ISODate("2017-10-18T07:14:53.449+0000"),
"delivery_mode" : "PUSH_NOTIFICATION",
"delivered" : false,
"parent" : DBRef("parents", ObjectId("59e6ff369ef9d46a91112878")),
"son" : DBRef("children", ObjectId("59e72ff0572ae72d8c063666"))
}
{
"_id" : ObjectId("59e6ff6d9ef9d46a91112893"),
"_class" : "es.bisite.usal.bulltect.persistence.entity.AlertEntity",
"level" : "WARNING",
"title" : "Token de acceso inv�lido.",
"payload" : "El token de acceso INSTAGRAM no es v�lido",
"create_at" : ISODate("2017-10-18T07:14:53.468+0000"),
"delivery_mode" : "PUSH_NOTIFICATION",
"delivered" : false,
"parent" : DBRef("parents", ObjectId("59e6ff369ef9d46a91112878")),
"son" : DBRef("children", ObjectId("59e72ffb572ae72d8c063669"))
}
请注意,我更改了 sons 引用的 OBjectIds 以匹配我创建的子集合。
child 收藏
{
"_id" : ObjectId("59e72ff0572ae72d8c063666"),
"name" : "Bob"
}
{
"_id" : ObjectId("59e72ffb572ae72d8c063669"),
"name" : "Tim"
}
由于您使用的是引用,因此您不能仅访问其他集合中的字段。所以我认为您缺少一些聚合步骤。
我做了以下事情:
db.getCollection('alerts').aggregate(
{
$unwind:"$son"
},
{
$group:
{
_id:{
son: "$son",
level: "$level"
},
count: { $sum: 1 }
}
},
{
$group:
{
_id:{
son: "$_id.son"
},
alerts: { $addToSet: {
level: "$_id.level",
count: "$count"
}}
}
},
{ $addFields: { sonsArray: { $objectToArray: "$_id.son" } } },
{ $match: { "sonsArray.k": "$id"} },
{ $lookup: { from: "children", localField: "sonsArray.v", foreignField: "_id", as: "name" } }
)
并得到以下 json 结果:
{
"_id" : {
"son" : DBRef("children", ObjectId("59e72ffb572ae72d8c063669"))
},
"alerts" : [
{
"level" : "WARNING",
"count" : NumberInt(1)
}
],
"sonsArray" : [
{
"k" : "$ref",
"v" : "children"
},
{
"k" : "$id",
"v" : ObjectId("59e72ffb572ae72d8c063669")
}
],
"name" : [
{
"_id" : ObjectId("59e72ffb572ae72d8c063669"),
"name" : "Tim"
}
]
}
{
"_id" : {
"son" : DBRef("children", ObjectId("59e72ff0572ae72d8c063666"))
},
"alerts" : [
{
"level" : "INFO",
"count" : NumberInt(1)
},
{
"level" : "WARNING",
"count" : NumberInt(1)
}
],
"sonsArray" : [
{
"k" : "$ref",
"v" : "children"
},
{
"k" : "$id",
"v" : ObjectId("59e72ff0572ae72d8c063666")
}
],
"name" : [
{
"_id" : ObjectId("59e72ff0572ae72d8c063666"),
"name" : "Bob"
}
]
}
如果您想删除额外创建的字段(例如 sonsArray 等),您可以添加一个 $project
管道来清理
您的结果。
<强>2。如果您有旧版本的 mongodb,则可以更改数据结构。
如果不使用这样的引用:
"son" : DBRef("children", ObjectId("59e72ffb572ae72d8c063669"))
您可以将儿子的 objectId 添加为数组,如下所示:
"sonId" : [
ObjectId("59e72ff0572ae72d8c063666")
]
然后您可以按如下方式进行聚合:
db.getCollection('alerts').aggregate(
{
$unwind:"$sonId"
},
{
$group:
{
_id:{
sonId: "$sonId",
level: "$level"
},
count: { $sum: 1 }
}
},
{
$group:
{
_id:{
sonId: "$_id.sonId"
},
alerts: { $addToSet: {
level: "$_id.level",
count: "$count"
}}
}
},
{ $lookup: { from: "children", localField: "_id.sonId", foreignField: "_id", as: "son" } }
)
这是您正在寻找的东西吗?
关于spring - 如何在 Spring MongoDB 聚合上投影 DBRef?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46790733/