简体   繁体   English

如何使用MongoDB Java驱动程序对ISODate属性的dayOfYear进行分组?

[英]How to use MongoDB Java driver to group by dayOfYear on ISODate attributes?

How to use mongodb java driver to compare dayOfYear of two ISODate objects? 如何使用mongodb java驱动程序比较两个ISODate对象的dayOfYear?

Here are my docs 这是我的文档

{"name": "hello", "count": 4, "TIMESTAMP": ISODate("2017-10-02T02:00:35.098Z")}
{"name": "hello", "count": 5, "TIMESTAMP": ISODate("2017-10-02T02:00:35.098Z")}
{"name": "goodbye", "count": 6, "TIMESTAMP": ISODate("2017-10-01T02:00:35.098Z")}
{"name": "foo", "count": 6, "TIMESTAMP": ISODate("2017-10-02T02:00:35.098Z")}

I want to compare the day in "TIMESTAMP" to perform some aggregation 我想比较“ TIMESTAMP”中的日期以执行一些汇总

 Bson match = Aggregates.match(eq("name": "hello"));
 Bson group = Aggregates.group(new Document("name", "$name"), Accumulators.sum("total", 1));

collection.aggregate(Arrays.asList(match, group))

Now I am not sure how to do this aggregation for all the records that belongs to particular day? 现在,我不确定如何对属于特定日期的所有记录进行此汇总?

so my expected result for "2017-10-02" is 所以我对“ 2017-10-02”的预期结果是

[{"_id": {"name":"hello"}, "total": 9}, {"_id": {"name":"foo"}, "total": 6}]

Given the following documents: 鉴于以下文件:

{"name": "hello", "count": 4, "TIMESTAMP": ISODate("2017-10-02T02:00:35.098Z")}
{"name": "hello", "count": 5, "TIMESTAMP": ISODate("2017-10-02T02:00:35.098Z")}
{"name": "goodbye", "count": 6, "TIMESTAMP": ISODate("2017-10-01T02:00:35.098Z")}
{"name": "foo", "count": 6, "TIMESTAMP": ISODate("2017-10-02T02:00:35.098Z")}

The following command ... 以下命令...

db.getCollection('dayOfYear').aggregate([

    // project dayOfYear as an attribute
    { $project: { name: 1, count: 1, dayOfYear: { $dayOfYear: "$TIMESTAMP" } } },

    // match documents with dayOfYear=275
    { $match: { dayOfYear: 275 } },

    // sum the count attribute for the selected day and name
    { $group : { _id : { name: "$name" }, total: { $sum: "$count" } } } 

])

... will return: ... 将返回:

{
    "_id" : {
        "name" : "foo"
    },
    "total" : 6
}

{
    "_id" : {
        "name" : "hello"
    },
    "total" : 9
}

I think this meets the requirement expressed in your OP. 认为这符合您在OP中表达的要求。

Here's the same command expressed using the MongoDB Java driver: 这是使用MongoDB Java驱动程序表达的相同命令:

MongoCollection<Document> collection = mongoClient.getDatabase("stackoverflow").getCollection("dayOfYear");

Document project = new Document("name", 1)
        .append("count", 1)
        .append("dayOfYear", new Document("$dayOfYear", "$TIMESTAMP"));

Document dayOfYearMatch = new Document("dayOfYear", 275);

Document grouping = new Document("_id", "$name").append("total", new Document("$sum", "$count"));

AggregateIterable<Document> documents = collection.aggregate(Arrays.asList(
        new Document("$project", project),
        new Document("$match", dayOfYearMatch),
        new Document("$group", grouping)
));

for (Document document : documents) {
    logger.info("{}", document.toJson());
}

Update based on this comment: 根据此评论进行更新

One of the problems with project is that it only include fields you specify . 项目的问题之一是它仅包含您指定的字段。 The above input is just an example. 以上输入仅是示例。 I have 100 fields in my doc I can't sepecify every single one so if I use project I have to specify all 100 fields in addition to "dayOfYear" field. 我的文档中有100个字段,我无法将每个字段都分隔开,因此,如果我使用项目,则除了“ dayOfYear”字段外,还必须指定所有100个字段。 – user1870400 11 mins ago – user1870400 11分钟前

You can use the following command to return the same output but without a $project stage: 您可以使用以下命令返回相同的输出,但没有$project阶段:

db.getCollection('dayOfYear').aggregate([
    // ignore any documents which do not match dayOfYear=275
    { "$redact": {
        "$cond": {
             if: { $eq: [ { $dayOfYear: "$TIMESTAMP" }, 275 ] },
             "then": "$$KEEP",
             "else": "$$PRUNE"
        }
    }},

    // sum the count attribute for the selected day
    { $group : { _id : { name: "$name" }, total: { $sum: "$count" } } } 

])

Here's that command in its 'Java form': 这是“ Java形式”的命令:

MongoCollection<Document> collection = mongoClient.getDatabase("stackoverflow").getCollection("dayOfYear");

Document redact = new Document("$cond", new Document("if", new Document("$eq", Arrays.asList(new Document("$dayOfYear", "$TIMESTAMP"), 275)))
        .append("then", "$$KEEP")
        .append("else", "$$PRUNE"));

Document grouping = new Document("_id", "$name").append("total", new Document("$sum", "$count"));

AggregateIterable<Document> documents = collection.aggregate(Arrays.asList(
        new Document("$redact", redact),
        new Document("$group", grouping)
));

for (Document document : documents) {
    logger.info("{}", document.toJson());
}

Note: Depending on the size of your collection/your non functional requirements/etc you may want to consider the performance of these solutions and either (a) add a match stage before you start projecting/redacting or (b) extract dayOfYear into its own attribute so that you can avoid this complexity entirely. 注意:根据集合的大小/您的非功能性要求/等,您可能要考虑这些解决方案的性能,并且(a)在开始投影/编辑之前添加匹配阶段,或者(b)将dayOfYear提取为自己的属性,这样您就可以完全避免这种复杂性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM