2016-03-02 50 views
0

我對MongoDB比較陌生,我試圖創建一個查詢,我雖然會很瑣碎(好吧,用SQL就可以了),但我可以'完成。MongoDB:在分組後獲取最大版本號的條目

因此有一個集合patients在這個集合中單個patient是使用id屬性標識的。 (不是mongodbs _id !!)可以有多個版本的單個patient,他的版本是由meta.versionId字段決定的。

爲了查詢所有「當前版本的患者」,我需要獲得每patient與特定id最大versionId

到目前爲止,我已經得到了這個:

AggregateIterable<Document> allPatients = db.getCollection("patients").aggregate(Arrays.asList(
      new Document("$group", new Document("_id", "$id") 
      .append("max", new Document("$max", "$meta.versionId"))))); 

    allPatients.forEach(new Block<Document>() { 
     @Override 
     public void apply(final Document document) { 
      System.out.println(document.toJson()); 
     } 
    }); 

導致下面的輸出(用我有限的測試數據):

{ "_id" : "2.25.260185450267055504591276882440338245053", "max" : "5" } { "_id" : "2.25.260185450267055504591276882441338245099", "max" : "0" }

似乎工作至今,但我需要獲得整個patients集合。 現在我只知道id : 2.25.260185450267055504591276882440338245053的最大版本是「5」,依此類推。當然,我現在可以爲每個單獨的條目創建一個自己的查詢,並從mongodb中順序獲取每個文檔的特定id/versionId -combo,但這看起來像是一個可怕的解決方案!有沒有其他的方法來完成它?

回答

1

如果你知道你想要檢索的列,說病人的姓名,地址,等我想你可以添加這些列在文檔與值1

AggregateIterable<Document> allPatients = db.getCollection("patients").aggregate(Arrays.asList(
      new Document("$group", new Document("_id", "$id") 
      .append("max", new Document("$max", "$meta.versionId")).append("name",1).append("address",1)))); 
+0

這是真的,但不幸的是我正在處理[FHIRs患者](https://www.hl7.org/fhir/patient.html)資源的配置文件,其結構相當複雜。所以,我更喜歡不同的方法。 –

1

,可以爲你工作的一種方法將首先使用$sort管道運營商訂購由meta.versionId字段獲取的文檔。但是請注意,$sort階段的內存限制爲100兆字節。默認情況下,如果超過此限制,$sort將產生錯誤。

要允許大型數據集的處理,設置allowDiskUse選項設置爲true,使$sort操作寫入臨時文件。有關詳細信息,請參閱aggregate()方法中的allowDiskUse選項。

排序後,您就可以組有序的文檔,使用$first$last運營商(根據以前的排序方向),以獲得其他領域進行聚合。

考慮運行以下蒙戈外殼流水線操作的 證明這一概念的方式:

蒙戈外殼

pipeline = [ 
    { "$sort": {"meta.versionId": -1}}, // order the documents by the versionId field descending 
    { 
     "$group": { 
      "_id": "$id", 
      "max": { "$first": "$meta.versionId" }, // get the maximum versionId 
      "active": { "$first": "$active" }, // Whether this patient's record is in active use 
      "name": { "$first": "$name" }, // A name associated with the patient 
      "telecom": { "$first": "$telecom" }, // A contact detail for the individual 
      "gender": { "$first": "$gender" }, // male | female | other | unknown 
      "birthDate": { "$first": "$birthDate" } // The date of birth for the individual 
      /* 
       And many other fields 
      */ 
     } 
    } 
] 
db.patients.aggregate(pipeline); 

Java測試實施

public class JavaAggregation { 
    public static void main(String args[]) throws UnknownHostException { 

     MongoClient mongo = new MongoClient(); 
     DB db = mongo.getDB("test"); 

     DBCollection coll = db.getCollection("patients"); 

     // create the pipeline operations, first with the $sort 
     DBObject sort = new BasicDBObject("$sort", 
          new BasicDBObject("meta.versionId", -1) 
         ); 

     // build the $group operations 
     DBObject groupFields = new BasicDBObject("_id", "$id"); 
     groupFields.put("max", new BasicDBObject("$first", "$meta.versionId")); 
     groupFields.put("active", new BasicDBObject("$first", "$active")); 
     groupFields.put("name", new BasicDBObject("$first", "$name")); 
     groupFields.put("telecom", new BasicDBObject("$first", "$telecom")); 
     groupFields.put("gender", new BasicDBObject("$first", "$gender")); 
     groupFields.put("birthDate", new BasicDBObject("$first", "$birthDate")); 
     // append any other necessary fields 

     DBObject group = new BasicDBObject("$group", groupFields); 
     List<DBObject> pipeline = Arrays.asList(sort, group); 

     AggregationOutput output = coll.aggregate(pipeline); 

     for (DBObject result : output.results()) { 
      System.out.println(result); 
     } 
    } 
} 
+0

看起來像上面一樣,只是排序。所以我想沒有可能獲得所有的領域,除了自己定義它們,對吧? –

+0

@FelixCullen不幸的是沒有。瞭解管道的工作方式;當執行一個管道時,MongoDB將管理員彼此連接起來。 ''Pipe''這裏的含義是:操作符的輸出成爲後面的操作符的輸入。每個操作員的結果都是一個新的文檔集合。因此,當你想要在一個組管道中獲得字段時,唯一的方法是使用僅在該階段的管道中可用的累加器運算符,以及使用'$ first'或'$ last'的取決於命令的累加器運算符的文件進入管道。 – chridam