spring - 如何在 Spring MongoDB 聚合上投影 DBRef?

标签 spring mongodb spring-mongo spring-mongodb

我在 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 属性中包含整个嵌入的子实体。

这是警报集合的结构。

enter image description here

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/

相关文章:

java - 为什么 Spring Data 会进行过多的查询?

javascript - Mongo 拉入 Meteor 不拉动

spring - 使用 spring mongo 进行分片

java - 如何使用 Spring+Mongo 更新和添加到子文档列表

java - 使用 Hibernate 建模 Java 类的最佳实践是什么?

java - Spring Autowiring 无法看到上下文 bean,除非在基础包上定义了组件扫描

javascript - 使用 $set 中的变量使用 node.js 更新 mongodb

mongodb - 应该如何声明上下文?

java - 使用 Spring MongoTemplate 在 mongo 中插入数据时获取 java.lang.NoSuchMethodError : org. springframework.cglib.core.ReflectUtils.defineClass

java - 在 Tomcat 服务器上的 Spring 应用程序中获取端口号和主机名