2017-10-17 3 views
0

Ich habe die folgende Aggregation in einer MongoDB Schale getan für jeden Benutzer die Anzahl der Alarme von jeder Art zu erhalten:Wie Projekt DBRef auf Spring MongoDB Aggregation?

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

       } 
     } 
     ) 

ich es Spring Data MongoDB übersetzt wie folgt:

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; 

Was ich nicht klar habe und ich kann es nicht zum Laufen bringen, ist, die Kennung und wenn möglich den Namen des Benutzers (Sohn Variable) zu projizieren.

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; 

} 

aber in der ID-Eigenschaft die gesamte eingebettete untergeordnete Entität.

Dies ist die Struktur der Sammlung von Warnungen.

enter image description here

JSON-Benachrichtigungen Format:

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

Wer weiß, wie ich kann dieser Ansatz?

Dank im Voraus

+0

Können Sie ein JSON-Beispiel Ihrer Warnmeldungssammlung einfügen? –

+0

Von dem Bild, das Sie eingefügt haben, kann ich nicht sehen, wie Sohn ein Array ist, weil Sie sich in Ihrer Aggregation entspannen. Es ist besser, wenn Sie den JSON anstelle eines Bildes einfügen. –

+0

Ich kann die Aggregationen in MongoDB nicht wirklich beherrschen, es ist die einzige Möglichkeit, das gewünschte Ergebnis zu erzielen. Aber meine Frage konzentriert sich mehr auf den letzten Teil der Projektion. Ich kann die ID des DBRef-Felds nicht abrufen. –

Antwort

2

1. MongoDB Version 3.4

Dies sind die folgenden Sammlungen ich Ihren Anwendungsfall zu reproduzieren erstellt:

Alerts Sammlung

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

Hinweis Ich habe die OBjectIds der Söhne ref passend zu der von mir erstellten Kinderkollektion.

Kinder Sammlung

{ 
    "_id" : ObjectId("59e72ff0572ae72d8c063666"), 
    "name" : "Bob" 
} 
{ 
    "_id" : ObjectId("59e72ffb572ae72d8c063669"), 
    "name" : "Tim" 
} 

Da Sie eine Referenz verwenden, können Sie nicht nur ein Feld aus der anderen Sammlung zugreifen. Also ich denke, dass Sie einige Aggregationsschritte vermissen.

Ich habe die folgenden:

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

und erhielt die folgenden Ergebnisse als 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" 
     } 
    ] 
} 

Wenn Sie die Felder loswerden wollen, die zusätzlich wie sonsArray geschaffen, wo usw. können Sie Fügen Sie eine $project Pipeline zu clean Ihr Ergebnis hinzu.


2. Wenn Sie ältere Versionen von mongodb und Sie können Ihre Datenstruktur ändern.

Wenn stattdessen eine Referenz wie folgt zu verwenden:

"sonId" : [ 
     ObjectId("59e72ff0572ae72d8c063666") 
    ] 

dann können Sie Ihre Aggregation tun:

"son" : DBRef("children", ObjectId("59e72ffb572ae72d8c063669")) 

Sie die objectId des Sohnes/s als Array wie folgt hinzufügen wie folgt:

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

Ist das etwas, das Sie suchen?

+0

Es ist perfekt, das Problem ist, dass ich eine solche aktuelle Version von Mongodb nicht verwenden kann. Anscheinend wurde diese Stufe "$ addFields" in Version 3.4 hinzugefügt. Ist es möglich, es für frühere Versionen anders zu machen? –

+0

Ich fürchte, es ist nicht möglich, denn selbst wenn ich Ihnen eine Alternative für die "$ addFields" zur Verfügung stelle (zum Beispiel durch eine längere "$ project" -Phase), stoßen Sie auf die nächste, die " $ objectToArray ". Dies ist auch nur in 3.4 möglich. Vielleicht ist das Grund genug, auf die neueste Mongo-Version upzugraden. Es könnte nur mit 3.2 funktionieren, wenn Sie mit der Änderung Ihres Schemas flexibel sind. –

+0

Wenn Sie daran interessiert sind, Ihr Schema zu ändern, kann ich mehr dazu ausführen. –