我有三个查询按货币和价格/利润分组获取所需数据。
一项查询在230 000项上花费约1.3秒。
一个项目如下:
{
"_id" : ObjectId("590e59fca0404a6e5577302b"),
"make_name" : "Peugeot",
"model_name" : "307",
"car_id" : NumberInt("396554354"),
"title" : "Sell",
"description" : "Cool",
"site_name" : "olx.ua",
"first_registration" : ISODate("2002-01-01T00:00:00.000Z"),
"fuel" : "Petrol",
"mileage" : NumberInt("250000"),
"category" : "Limousine",
"horse_power" : null,
"cubic_capacity" : NumberInt("1600"),
"transmission" : "Manual",
"price" : NumberInt("5050"),
"currency" : "USD",
"negotiable" : true,
"profit" : NumberInt("-8"),
"owners_count" : NumberInt("2"),
"color" : NumberInt("3"),
"condition" : NumberInt("4"),
"updated_at" : ISODate("2017-06-01T03:51:34.000Z"),
"rear_camera" : false,
"ABS" : false,
"four_wheel_drive" : false,
"bluetooth" : false,
"board_computer" : false,
"cd_player" : false,
"electric_mirrors" : false,
"electric_windows" : true,
"parking_assistance" : false,
"handsfree" : false,
"guarantee" : false,
"head_up_display" : false,
"has_inspection" : false,
"air_conditioning" : false,
"alloy_wheel_rims" : false,
"multi_func_steering_wheel" : false,
"navigation" : false,
"non_smoking_car" : false,
"panorama_roof" : false,
"particle_filter" : false,
"rain_sensor" : false,
"full_service_history" : false,
"power_steering" : false,
"sunroof" : false,
"seat_heating" : false,
"sports_suspension" : false,
"sports_seats" : false,
"pre_heating" : false,
"start_stop" : false,
"taxi" : false,
"tax_paid" : true,
"cruise_control" : false,
"xenon_headlights" : true,
"security" : false,
"sport_package" : false,
"business" : true,
"damaged" : false,
"price_100" : 5000,
"profit_100" : 0
},
我的查询是:
db.cars.aggregate([{
'$match': {
'$and': [
{ 'first_registration': { '$gte': ISODate("2000-01-01") } },
{ 'first_registration': { '$lte': ISODate("2017-01-01") } },
{ 'price': { '$gte': 0 } },
{ 'price': { '$lte': 60000 } },
{ 'profit': { '$exists': true } },
{ 'profit': { '$gte': -20000 } },
{ 'profit': { '$lte': 30000 } },
{ 'updated_at': { '$gte': ISODate("2017-06-04") } },
{ 'currency': 'USD' },
{ 'damaged': false }]
}
},
{
'$group': {
'_id': {
'price': {
'$subtract': ['$price',
{ '$mod': ['$price', 100] }]
},
'profit': { '$subtract': ['$profit', { '$mod': ['$profit', 100] }] }
},
'car_id': { '$first': '$car_id' },
'currency': { '$first': '$currency' },
'price': { '$first': '$price' },
'profit': { '$first': '$profit' }
}
}])
我需要在一组指定的价格/利润中获得第一项。
示例:10辆车的价格/利润为100-160美元,因此只有一辆车会被退回进行此类查询,因为这辆车的组(数据)点价格为100,利润为100.我希望这样做。
首先"匹配"查询大约需要0.012秒才能获得15万个项目。
所以我认为问题出在群组查询中。
我尝试预先构建数学运算减法和mod:
db.cars.find({
'profit': {'$exists': true},
'price_100': {'$exists': false}, }).snapshot().forEach(function(doc){
db.cars.update({_id:doc._id}, {$set:{
"price_100":doc.price - (doc.price % 100),
"profit_100": doc.profit - (doc.profit % 100)
}});
});
然后我的查询开始看起来像:
db.cars.aggregate(
[
{
'$match': {
'$and': [
{ 'first_registration': { '$gte': ISODate("2000-01-01") } },
{ 'first_registration': { '$lte': ISODate("2017-01-01") } },
{ 'price': { '$gte': 0 } },
{ 'price': { '$lte': 60000 } },
{ 'profit': { '$exists': true } },
{ 'profit': { '$gte': -20000 } },
{ 'profit': { '$lte': 30000 } },
{ 'updated_at': { '$gte': ISODate("2017-06-04") } },
{ 'currency': 'USD' },
{ 'damaged': false }]
}
},
{
'$group': {
'_id': {
'price': '$price_100',
'profit': '$profit_100',
},
'car_id': { '$first': '$car_id' },
'currency': { '$first': '$currency' },
'price': { '$first': '$price' },
'profit': { '$first': '$profit' }
}
}])
不幸的是,比原来的需要300毫秒。
解释我的问题:
{
"stages" : [
{
"$cursor" : {
"query" : {
"$and" : [
{
"first_registration" : {
"$gte" : ISODate("2000-01-01T00:00:00.000Z")
}
},
{
"first_registration" : {
"$lte" : ISODate("2017-01-01T00:00:00.000Z")
}
},
{
"price" : {
"$gte" : 0
}
},
{
"price" : {
"$lte" : 60000
}
},
{
"profit" : {
"$exists" : true
}
},
{
"profit" : {
"$gte" : -20000
}
},
{
"profit" : {
"$lte" : 30000
}
},
{
"updated_at" : {
"$gte" : ISODate("2017-06-04T00:00:00.000Z")
}
},
{
"currency" : "USD"
},
{
"damaged" : false
}
]
},
"fields" : {
"car_id" : NumberInt("1"),
"currency" : NumberInt("1"),
"price" : NumberInt("1"),
"price_100" : NumberInt("1"),
"profit" : NumberInt("1"),
"profit_100" : NumberInt("1"),
"_id" : NumberInt("0")
},
"queryPlanner" : {
"plannerVersion" : NumberInt("1"),
"namespace" : "master_test.cars",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"currency" : {
"$eq" : "USD"
}
},
{
"damaged" : {
"$eq" : false
}
},
{
"first_registration" : {
"$lte" : ISODate("2017-01-01T00:00:00.000Z")
}
},
{
"price" : {
"$lte" : 60000
}
},
{
"profit" : {
"$lte" : 30000
}
},
{
"first_registration" : {
"$gte" : ISODate("2000-01-01T00:00:00.000Z")
}
},
{
"price" : {
"$gte" : 0
}
},
{
"profit" : {
"$gte" : -20000
}
},
{
"updated_at" : {
"$gte" : ISODate("2017-06-04T00:00:00.000Z")
}
},
{
"profit" : {
"$exists" : true
}
}
]
},
"winningPlan" : {
"stage" : "COLLSCAN",
"filter" : {
"$and" : [
{
"currency" : {
"$eq" : "USD"
}
},
{
"damaged" : {
"$eq" : false
}
},
{
"first_registration" : {
"$lte" : ISODate("2017-01-01T00:00:00.000Z")
}
},
{
"price" : {
"$lte" : 60000
}
},
{
"profit" : {
"$lte" : 30000
}
},
{
"first_registration" : {
"$gte" : ISODate("2000-01-01T00:00:00.000Z")
}
},
{
"price" : {
"$gte" : 0
}
},
{
"profit" : {
"$gte" : -20000
}
},
{
"updated_at" : {
"$gte" : ISODate("2017-06-04T00:00:00.000Z")
}
},
{
"profit" : {
"$exists" : true
}
}
]
},
"direction" : "forward"
},
"rejectedPlans" : [ ]
}
}
},
{
"$group" : {
"_id" : {
"price" : "$price_100",
"profit" : "$profit_100"
},
"car_id" : {
"$first" : "$car_id"
},
"currency" : {
"$first" : "$currency"
},
"price" : {
"$first" : "$price"
},
"profit" : {
"$first" : "$profit"
}
}
}
],
"ok" : 1
}
为什么有人会想到3个查询?我的数据库中有3种货币:USD,EUR和PLN,因此我提出了3个请求。目前,我不知道如何统一查询。
NEIL更新:
在实施建议后,我能够将时间从1.3秒减少到1秒。
查询看起来像:
db.cars.aggregate([{
'$match': {
'$and': [
{ 'first_registration': { '$gte': ISODate("2000-01-01"), '$lte': ISODate("2017-01-01") } },
{ 'price': { '$gte': 0, '$lte': 60000 } },
{ 'profit': { '$exists': true, '$gte': -20000, '$lte': 30000 } },
{ 'updated_at': { '$gte': ISODate("2017-06-04") } },
{ 'currency': 'USD' },
{ 'damaged': false }]
}
},
{
'$group': {
'_id': {
'price': {
'$subtract': ['$price',
{ '$mod': ['$price', 100] }]
},
'profit': { '$subtract': ['$profit', { '$mod': ['$profit', 100] }] }
},
'car_id': { '$first': '$car_id' },
'currency': { '$first': '$currency' },
'price': { '$first': '$price' },
'profit': { '$first': '$profit' }
}
}])
并解释:
{
"stages" : [
{
"$cursor" : {
"query" : {
"$and" : [
{
"first_registration" : {
"$gte" : ISODate("2000-01-01T00:00:00.000Z"),
"$lte" : ISODate("2017-01-01T00:00:00.000Z")
}
},
{
"price" : {
"$gte" : 0,
"$lte" : 60000
}
},
{
"profit" : {
"$exists" : true,
"$gte" : -20000,
"$lte" : 30000
}
},
{
"updated_at" : {
"$gte" : ISODate("2017-06-04T00:00:00.000Z")
}
},
{
"currency" : "USD"
},
{
"damaged" : false
}
]
},
"fields" : {
"car_id" : NumberInt("1"),
"currency" : NumberInt("1"),
"price" : NumberInt("1"),
"profit" : NumberInt("1"),
"_id" : NumberInt("0")
},
"queryPlanner" : {
"plannerVersion" : NumberInt("1"),
"namespace" : "master_test.cars",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"currency" : {
"$eq" : "USD"
}
},
{
"damaged" : {
"$eq" : false
}
},
{
"first_registration" : {
"$lte" : ISODate("2017-01-01T00:00:00.000Z")
}
},
{
"price" : {
"$lte" : 60000
}
},
{
"profit" : {
"$lte" : 30000
}
},
{
"first_registration" : {
"$gte" : ISODate("2000-01-01T00:00:00.000Z")
}
},
{
"price" : {
"$gte" : 0
}
},
{
"profit" : {
"$gte" : -20000
}
},
{
"updated_at" : {
"$gte" : ISODate("2017-06-04T00:00:00.000Z")
}
},
{
"profit" : {
"$exists" : true
}
}
]
},
"winningPlan" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"first_registration" : {
"$lte" : ISODate("2017-01-01T00:00:00.000Z")
}
},
{
"price" : {
"$lte" : 60000
}
},
{
"profit" : {
"$lte" : 30000
}
},
{
"first_registration" : {
"$gte" : ISODate("2000-01-01T00:00:00.000Z")
}
},
{
"price" : {
"$gte" : 0
}
},
{
"profit" : {
"$gte" : -20000
}
},
{
"profit" : {
"$exists" : true
}
}
]
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"updated_at" : 1,
"currency" : 1,
"damaged" : 1
},
"indexName" : "updated_at_1_currency_1_damaged_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"updated_at" : [ ],
"currency" : [ ],
"damaged" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : NumberInt("2"),
"direction" : "forward",
"indexBounds" : {
"updated_at" : [
"[new Date(1496534400000), new Date(9223372036854775807)]"
],
"currency" : [
"[\"USD\", \"USD\"]"
],
"damaged" : [
"[false, false]"
]
}
}
},
"rejectedPlans" : [ ]
}
}
},
{
"$group" : {
"_id" : {
"price" : {
"$subtract" : [
"$price",
{
"$mod" : [
"$price",
{
"$const" : 100
}
]
}
]
},
"profit" : {
"$subtract" : [
"$profit",
{
"$mod" : [
"$profit",
{
"$const" : 100
}
]
}
]
}
},
"car_id" : {
"$first" : "$car_id"
},
"currency" : {
"$first" : "$currency"
},
"price" : {
"$first" : "$price"
},
"profit" : {
"$first" : "$profit"
}
}
}
],
"ok" : 1
}
在预建的字段price_100和profit_100上运行仍然是1.3秒,但现在我们对于非预建的查询少了300毫秒,很好!