Java 未使用日期的嵌入文档索引
我是使用MongoDB的新手,我收集了这类文档:Java 未使用日期的嵌入文档索引,java,mongodb,spring-data,aggregation-framework,spring-data-mongodb,Java,Mongodb,Spring Data,Aggregation Framework,Spring Data Mongodb,我是使用MongoDB的新手,我收集了这类文档: { "_id" : { "coordinate" : { "latitude" : 532144, "longitude" : -33333 }, "margin" : "N" }, "prices" : [ { "type" : "GAS_95", "price" : 1370, "date" : ISODate("2014-05-
{
"_id" : {
"coordinate" : {
"latitude" : 532144,
"longitude" : -33333
},
"margin" : "N"
},
"prices" : [
{
"type" : "GAS_95",
"price" : 1370,
"date" : ISODate("2014-05-03T18:39:13.635Z")
},
{
"type" : "DIESEL_A",
"price" : 1299,
"date" : ISODate("2014-05-03T18:39:13.635Z")
},
{
"type" : "DIESEL_A_NEW",
"price" : 1350,
"date" : ISODate("2014-05-03T18:39:13.635Z")
},
{
"type" : "GAS_98",
"price" : 1470,
"date" : ISODate("2014-05-03T18:39:13.635Z")
}
]
}
我需要检索特定日期的价格,因此我运行以下查询:
db.gasStation.aggregate(
{ "$unwind" : "$prices"},
{ "$match" : {
"_id" : {
"coordinate" : {
"latitude" : 532144 ,
"longitude" : -33333} ,
"margin" : "N"
} ,
"prices.date" : {
"$gte" : ISODate("2014-05-02T23:00:00.000Z") ,
"$lte" : ISODate("2014-05-03T22:59:59.999Z")
}
}
db.gasStation.aggregate([
{ "$match" : {
"_id" : {
"coordinate" : {
"latitude" : 532144 ,
"longitude" : -33333} ,
"margin" : "N"
}
}},
{ "$unwind" : "$prices"},
{ "$match" : {
"prices.date" : {
"$gte" : ISODate("2014-05-02T23:00:00.000Z") ,
"$lte" : ISODate("2014-05-03T22:59:59.999Z")
}
}}
], {explain:true});
}))
一切正常,我检索了文档,但我认为我的文档可以改进,我尝试为_id和prices创建索引。日期:
db.gasStation.ensureIndex( {
"_id" : 1,
"prices.date" : 1
} )
之后,我尝试查看是否在使用explain选项的查询中使用索引,但未使用任何索引:
{
"stages" : [
{
"$cursor" : {
"query" : {
},
"plan" : {
"cursor" : "BasicCursor",
"isMultiKey" : false,
"scanAndOrder" : false,
"allPlans" : [
{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"scanAndOrder" : false
}
]
}
}
},
{
"$unwind" : "$prices"
},
{
"$match" : {
"_id" : {
"coordinate" : {
"latitude" : 532144,
"longitude" : -33333
},
"margin" : "N"
},
"prices.date" : {
"$gte" : ISODate("2014-05-02T23:00:00Z"),
"$lte" : ISODate("2014-05-03T22:59:59.999Z")
}
}
}
],
"ok" : 1
}
是否有任何原因表明我的查询不适合使用索引?我在MongoDB文档中读到,唯一没有使用索引的管道是$group,但我没有使用该功能。我将引用以下文档: $match和$sort管道操作符可以利用索引 当它们出现在管道的开头时 资料来源: 在管道的开头没有$match或$sort,而是有$unwind操作。因此,索引在这里是无用的 编辑-详细说明: 仍然可以将部分匹配条件移动到管道的开头,以便使用索引
db.gasStation.aggregate([
{ "$match" : {
"_id" : {
"coordinate" : {
"latitude" : 532144 ,
"longitude" : -33333} ,
"margin" : "N"
}
}},
{ "$project": { "prices" : 1, "_id" : 0 } },
{ "$unwind" : "$prices"},
{ "$match" : {
"prices.date" : {
"$gte" : ISODate("2014-05-02T23:00:00.000Z") ,
"$lte" : ISODate("2014-05-03T22:59:59.999Z")
}
}}
],{explain:true});
但是,此处不需要此索引:
{"_id":1, "prices.date":1}
为什么??因为管道开头的$match只按_id进行过滤。在mongodb中,文档的_id会被自动索引,这就是将在本例中使用的索引
此外,您还可以通过使用$project操作符删除不必要的字段来进一步优化查询。如果不需要字段,请尽快将其删除。尝试重新安排聚合管道操作符。例如,此查询:
db.gasStation.aggregate(
{ "$unwind" : "$prices"},
{ "$match" : {
"_id" : {
"coordinate" : {
"latitude" : 532144 ,
"longitude" : -33333} ,
"margin" : "N"
} ,
"prices.date" : {
"$gte" : ISODate("2014-05-02T23:00:00.000Z") ,
"$lte" : ISODate("2014-05-03T22:59:59.999Z")
}
}
db.gasStation.aggregate([
{ "$match" : {
"_id" : {
"coordinate" : {
"latitude" : 532144 ,
"longitude" : -33333} ,
"margin" : "N"
}
}},
{ "$unwind" : "$prices"},
{ "$match" : {
"prices.date" : {
"$gte" : ISODate("2014-05-02T23:00:00.000Z") ,
"$lte" : ISODate("2014-05-03T22:59:59.999Z")
}
}}
], {explain:true});
生成此输出,它现在确实显示了一些索引用法:
{
"stages" : [
{
"$cursor" : {
"query" : {
"_id" : {
"coordinate" : {
"latitude" : 532144,
"longitude" : -33333
},
"margin" : "N"
}
},
"plan" : {
"cursor" : "IDCursor",
"indexBounds" : {
"_id" : [
[
{
"coordinate" : {
"latitude" : 532144,
"longitude" : -33333
},
"margin" : "N"
},
{
"coordinate" : {
"latitude" : 532144,
"longitude" : -33333
},
"margin" : "N"
}
]
]
}
}
}
},
{
"$unwind" : "$prices"
},
{
"$match" : {
"prices.date" : {
"$gte" : ISODate("2014-05-02T23:00:00Z"),
"$lte" : ISODate("2014-05-03T22:59:59.999Z")
}
}
}
],
"ok" : 1
关键是尝试让管道操作符(如管道开头的$match和$sort-up-front)使用索引来限制访问和传递到聚合其余部分的数据量。通过上述示例,您可以做更多的事情来提高性能,但这应该会让您对如何实现这一点有一个很好的了解。谢谢您的帮助!我试过了,效果很好!我只是想知道在这种情况下使用$elemMatch是否有助于稍微改进查询。但是我读到$elemMatch在索引方面也有一些问题。。。我担心的是,如果我有数千个价格,那么这个查询没有使用价格级别上的任何索引,如果我多次运行这个查询,我不知道性能如何。谢谢你的帮助!需要更多的阐述。但技术上是正确的。忘记文档中关于“优化”的内容。聚合管道中唯一的优化是“删除管道中其他地方未使用的字段”的第一条语句。其他提到的都是无用的编码技巧。不管怎样,我都会给它们编码。一个更完整的解释比一个错误的被接受的答案能让你获得更多的选票。有一个徽章要为此颁发。没错,让我知道。@NeilLunn你是对的,关于这个问题还有很多要说的。只是对其进行了编辑,以包含更详细的解释。非常感谢。