0

Comment utiliser le pilote mongodb java pour comparer dayOfYear de deux objets ISODate?Comment utiliser le pilote Java MongoDB pour grouper par dayOfYear sur les attributs ISODate?

Voici mes 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")} 

Je veux comparer le jour dans « TIMESTAMP » pour effectuer une agrégation

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)) 

Maintenant, je ne suis pas sûr de savoir comment faire cette agrégation pour tous les enregistrements qui appartient à un jour particulier?

donc mon résultat attendu pour "02/10/2017" est

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

Répondre

2

Compte tenu des documents suivants:

{"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")} 

La commande suivante ...

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" } } } 

]) 

... reviendra:

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

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

I pense que cela répond aux exigences exprimées dans votre OP.

est ici la même commande exprimée en utilisant le pilote 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()); 
} 

Mise à jour basé sur ce commentaire:

L'un des problèmes avec le projet est qu'il inclut uniquement les champs que vous spécifiez . L'entrée ci-dessus est juste un exemple. J'ai 100 champs dans mon document, je ne peux pas séparer chacun d'eux, donc si j'utilise le projet, je dois spécifier les 100 champs en plus du champ "dayOfYear". - user1870400 11 minutes il y a

Vous pouvez utiliser la commande suivante pour retourner la même sortie, mais sans étape $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" } } } 

]) 

Voici cette commande dans sa 'forme 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()); 
} 

Remarque: Selon la taille de votre collection/vos besoins non fonctionnels/etc, vous pouvez envisager la performance de ces solutions et soit (a) ajouter une étape de correspondance avant de commencer à projeter/rédiger ou (b) extraire dayOfYear dans son propre attribut afin d'éviter complètement cette complexité.

+0

Je ne peux pas voir la fonction dayOfYear dans mongodb Java driver. – user1870400

+0

@ user1870400 Il n'y a pas de fonction 'dayOfYear' dans le pilote Java mais si vous pouvez confirmer que la sortie de la commande fournie dans ma réponse ** est ** votre sortie désirée, je peux mettre à jour ma réponse avec le 'Java form' de cette commande. – glytching

+0

Ce que je cherchais, c'est de faire l'agrégation "sum" pour un jour particulier, donc j'ai besoin de passer un filtre qui filtre tout le document qui n'appartient pas à un jour donné.Par exemple, je veux additionner tous les documents qui ont un nom de match bonjour et le jour "2017-10-02". Si l'horodatage a une autre date, je ne veux pas qu'elle soit prise dans le compte pour l'agrégation. – user1870400