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

标签 java mongodb mongodb-query spring-data spring-mongodb

我想查询文档中数组元素(也可以包括子文档)的一个/多个匹配字段。

例如:

我的 Collection 包括以下文档:

{ 
    "_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和索引字段,但由于匹配条件,它返回数组的第一个匹配元素,匹配“name”:“test”或“date”大于等于dCriteria,但我想要的是同时满足两个条件。

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

最佳答案

MongoDB 将日期存储为 UTC,这通常也是存储日期的最佳实践,因为它允许在不同时区之间进行转换,而无需计算出原始起点。

因此,可以肯定的是,此处的实际日期确实是 UTC,但您传入的是从不同时区构造的值。驱动程序实际上使用纪元时间戳序列化 BSON 请求,并注明“日期”BSON 类型。这意味着您的输入现在因时区差异而“倾斜”。在本例中,减去 3 小时来代表 UTC,因此转换后的日期比您想象的早 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。

您几乎总是希望在查询中而不是在投影中进行元素匹配。然后可以使用 positional $ 来投影获得的“第一个”匹配。一旦您移动您的$elemMatch运算符(operator)到您的语句的查询部分。这可以确保当数组中没有任何元素实际符合您的条件时,您不会得到空数组。

关于java - 在 Java 中查询具有完全匹配字段 MongoDB 的数组元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25647834/

相关文章:

java - 自定义 LogBack 附加程序失败并出现 java.lang.ClassNotFoundException

java - android.content.ActivityNotFoundException : Unable to find explicit activity class { have you declared this activity in your AndroidManifest. xml?

java - 使用 UTF 字符编码 java 字符串\&\#232

mongodb - 如何使用 Doctrine ODM for MongoDB 设置我自己的 MongoId?

mongodb - 在 mongodb 中查找特定日期的数据

java - PrivateKey由 OpenSSL 生成为 RSACRTPrivateKey 对象

javascript - MongoDB 模式设计 - 巨大的列表

mongodb - 批量插入在 MongoDB 中是原子的吗

mongodb - Mongo - 使用包含点的键查找记录

mongodb - 限制在组中推送返回的项目