MongoDB:在分组后获取具有最大版本ID的条目

时间:2016-03-02 09:50:54

标签: java mongodb mongodb-query

我是MongoDB的新手,我正在尝试创建一个查询,我觉得这很简单(好吧,改为SQL它会)但我无法得到它完成。

因此,在此集合中有一个集合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集合。 现在我只知道patient最大版本是“5”,依此类推。当然,我现在可以为每个条目创建一个自己的查询,并从mongodb顺序获取特定id / versionId - 组合的每个{{1}}文档,但这似乎是一个可怕的解决方案!有没有其他方法可以完成它?

2 个答案:

答案 0 :(得分: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))));

答案 1 :(得分:1)

可能适用于您的方法是首先使用 $sort 管道运算符命令meta.versionId字段进入管道中的文档。但请注意, $sort 阶段的内存限制为100兆字节。默认情况下,如果超出此限制, $sort 将产生错误。

要允许处理大型数据集,请将allowDiskUse选项设置为true,以启用 $sort 操作以写入临时文件。有关详细信息,请参阅 aggregate() 方法中的allowDiskUse选项。

排序后,您可以对订购的文档进行分组,使用 $first $last 运算符进行汇总(具体取决于获得其他字段。

考虑运行以下mongo shell管道操作作为一种方式 展示这个概念:

Mongo shell

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