在Java中查询具有完全匹配字段MongoDB的数组元素

在Java中查询具有完全匹配字段MongoDB的数组元素,java,mongodb,mongodb-query,spring-data,spring-mongodb,Java,Mongodb,Mongodb Query,Spring Data,Spring Mongodb,我想查询一个数组元素(也可以包括子文档)的一个或多个匹配字段,该数组元素位于文档中 例如: 我的收藏包括以下文件: { "_id": 1, "index": 1, "elements":[ { "name":"test", "date":"Mon Sep 01 01:00:00 EEST 2014" , "tag":1 }, {

我想查询一个数组元素(也可以包括子文档)的一个或多个匹配字段,该数组元素位于文档中

例如:

我的收藏包括以下文件:

{ 
    "_id": 1, 
    "index": 1,
    "elements":[
        {
            "name":"test",
            "date":"Mon Sep 01 01:00:00 EEST 2014" , 
            "tag":1
        }, 
        {
            "name": "test2",
            "date": "Mon Sep 01 01:00:00 EEST 2014",
            "tag": 2
        },
        {
            "name": "test",
            "date": "Mon Sep 01 02:00:00 EEST 2014",
            "tag": 3
        }
    ]
},
{ 
    "_id":2, 
    "index":2, 
    "elements":[ 
        {
            "name":"test",
            "date":"Mon Sep 01 01:00:00 EEST 2014" ,
            "tag":1
        }, 
        {
            "name": "test2",
            "date": "Mon Sep 01 01:00:00 EEST 2014", 
            "tag":2
        },
        {   
            "name":"test",
            "date":"Mon Sep 01 01:10:00 EEST 2014", 
            "tag":3
        }
    ]
},
{ 
    "_id": 3,
    "index": 3,
    "elements": [ 
        {
            "name": "test",
            "date": "Mon Sep 01 01:00:00 EEST 2014", 
            "tag":1
        },
        { 
            "name": "test2",
            "date": "Mon Sep 01 01:00:00 EEST 2014", 
            "tag":2
        },
        {
            "name": "test",
            "date": "Mon Sep 01 01:10:00 EEST 2014", 
            "tag":3
        }
    ]
}

我希望我的查询结果返回如下文档:

{ 
    "_id":1,
    "index": 1,
    "elements":[
        { 
            "name":"test",
            "date":"Mon Sep 01 02:00:00 EEST 2014" ,
            "tag":3
        }
    ]
}
为此,我编写了一个查询

Date dCriteria = new SimpleDateFormat("dd/MM/yy HH:mm:ss").parse("01/09/2014 05:00:00");

Query find = new Query( Criteria.where("index").is(3) );  //To find matching documents
find.fields().elemMatch(
    "elements",
    Criteria.where("name").is("test").and("date").gte(dCriteria)));

mongotemplate.findOne( find, Document.class );
这意味着在MongoDB shell命令中:

db.collection.find(
    { "index": 3 },
    { "elements": { 
        "$elemMatch": {
            "name": "test", 
            "date": { 
                "$gte": { "$date":"2014-09-01T02:00:000Z" }
            }
        }
    }
 )          
但它返回以下结果:

{
    "_id": 0, 
    "index": 0, 
    "elements":[
        {
            "name": "test",
            "date": "Mon Sep 01 01:00:00 EEST 2014",
            "tag":1
        }
    ]
}
可以省略_id和索引文件,但由于匹配条件,它返回数组的第一个macting元素,匹配的“name”:“test”或“date”大于相等的dCriteria,但我希望同时匹配这两个条件


为了做到这一点,我必须使用$elemMatch操作符来查询数组元素中同时匹配多个字段的情况。但是我不知道如何在我的投影中使用它的语法。

MongoDB将日期存储为UTC,这通常也是存储日期的最佳实践,因为它允许在不计算原始原点的情况下转换到不同时区

因此,最确定的是,此处的实际日期确实是UTC,但您传递的是一个由不同时区构造的值。驱动程序实际使用历元时间戳序列化BSON请求,并注意“日期”BSON类型。这意味着您的输入现在被时区差异“扭曲”。在这种情况下,表示UTC的时间缩短了3小时,因此转换后的日期比您想象的早3小时

如果您有特定时区的日期的源数据,那么您需要首先将其转换为输入数据和用户界面中的表示数据,如果您希望以本地时间显示值

因此,转换或构造为UTC:

    // org.joda.time as Date constructor is deprecated
    Date dCriteria = new DateTime(2014,9,1,1,10,DateTimeZone.UTC).toDate();

    Query find = new Query( Criteria.where("index").is(3) );  //To find matching documents
    find.fields().elemMatch(
            "elements",
            Criteria.where("name").is("test").and("date").gte(dCriteria)
    );

    System.out.println(find);
如果不确定结果查询的结构,请打印出来进行一般调试。您真的应该在日志记录级别执行此操作,您可以在生产中抑制此操作

如上所述,这与您引用的shell查询相同,但您的代码不是这样的,因为它使用的是本地时间,而不是UTC


您几乎总是希望在查询中而不是在投影中进行元素匹配。一旦移动到语句的查询部分,就可以使用运算符投影获得的“第一个”匹配。这确保了当数组中的元素都不符合您的条件时,不会得到空数组。

嗨,尼尔,实际上我的问题不在于日期。我还知道mongo使用UTC格式,不在乎日期。我的问题是质疑结果。我也可以将$elemMatch条件放入搜索查询中,这样在投影之前就不会得到一个空文档,对吗。但问题来自于在数组元素中只获取匹配的数组元素。这意味着我应该使用(不确定)$elemMatch和另一个elemMatch运算符为我的查询获取匹配元素,其中包含字段名称和测试。@C.Kaya您的问题在于日期。获取错误元素的原因是时区差的调整时间。您应该能够通过基本上执行我在定义查询结束时所做的操作来判断。记录输出以查看序列化表单。您的代码将不会产生与您向shell发出的查询相同的结果。我所做的将是。我用我在帖子中使用的实际内容编辑了我的时间格式。下面是我使用过的匹配元素的查询:查询:{“索引”:1,“报警”:{“$elemMatch”:{“名称”:“Test1”,“日期”:{“$gte”:{“$date”:“2014-09-01T02:00:00.000Z”}}}}},字段:{“报警”:{“$elemMatch”:{“名称”:“Test1”,“日期”:{“$gte”:{“$date 2014-09-01T02:00:00.000Z”}}}},排序:null