ฉันมีคอลเลกชันT
2 ช่อง: Grade1
และGrade2
และฉันต้องการเลือกสิ่งที่มีเงื่อนไขGrade1 > Grade2
ฉันจะรับแบบสอบถามใน MySQL ได้อย่างไร
Select * from T Where Grade1 > Grade2
ฉันมีคอลเลกชันT
2 ช่อง: Grade1
และGrade2
และฉันต้องการเลือกสิ่งที่มีเงื่อนไขGrade1 > Grade2
ฉันจะรับแบบสอบถามใน MySQL ได้อย่างไร
Select * from T Where Grade1 > Grade2
คำตอบ:
คุณสามารถใช้ $ where โปรดทราบว่ามันจะค่อนข้างช้า (ต้องรันโค้ด Javascript ในทุกเร็กคอร์ด) ดังนั้นรวมกับเคียวรีที่จัดทำดัชนีหากทำได้
db.T.find( { $where: function() { return this.Grade1 > this.Grade2 } } );
หรือกะทัดรัดกว่า:
db.T.find( { $where : "this.Grade1 > this.Grade2" } );
คุณสามารถใช้$expr
ตามที่อธิบายไว้ในคำตอบล่าสุด
$where: function() { return this.Grade1 - this.Grade2 > variable }
อย่างไร?
db.T.find({$where: function() {return this.startDate == ISODate("2017-01-20T10:55:08.000Z");}});
ISODate("2017-01-20T10:55:08.000Z")
แต่<=
และ>=
ดูเหมือนการทำงาน มีความคิดอย่างไร
this.startDate.getTime() == ISODate("2017-01-20T10:55:08.000Z").getTime()
คุณสามารถใช้$ expr (ตัวดำเนินการเวอร์ชัน 3.6 mongo) เพื่อใช้ฟังก์ชันการรวมในแบบสอบถามปกติ
เปรียบเทียบquery operators
กับaggregation comparison operators
.
คำถามปกติ:
db.T.find({$expr:{$gt:["$Grade1", "$Grade2"]}})
แบบสอบถามการรวม:
db.T.aggregate({$match:{$expr:{$gt:["$Grade1", "$Grade2"]}}})
หากข้อความค้นหาของคุณประกอบด้วยตัว$where
ดำเนินการเท่านั้นคุณสามารถส่งผ่านได้ด้วยนิพจน์ JavaScript:
db.T.find("this.Grade1 > this.Grade2");
เพื่อประสิทธิภาพที่ดียิ่งขึ้นให้รันการดำเนินการรวมที่มี$redact
ไปป์ไลน์เพื่อกรองเอกสารที่ตรงตามเงื่อนไขที่กำหนด
$redact
ท่อรวมเอาการทำงานของ$project
และ$match
จะใช้สนาม redaction ระดับที่มันจะคืนเอกสารทั้งหมดที่ตรงกับเงื่อนไขการใช้$$KEEP
และลบจากผลการท่อเหล่านั้นที่ไม่ตรงกับการใช้$$PRUNE
ตัวแปร
การเรียกใช้การดำเนินการรวมต่อไปนี้จะกรองเอกสารได้อย่างมีประสิทธิภาพมากกว่าการใช้$where
สำหรับคอลเลกชันขนาดใหญ่เนื่องจากใช้ไปป์ไลน์เดียวและตัวดำเนินการ MongoDB ดั้งเดิมแทนที่จะใช้การประเมิน JavaScript ด้วย$where
ซึ่งอาจทำให้การสืบค้นช้าลง:
db.T.aggregate([
{
"$redact": {
"$cond": [
{ "$gt": [ "$Grade1", "$Grade2" ] },
"$$KEEP",
"$$PRUNE"
]
}
}
])
ซึ่งเป็นเวอร์ชันที่ง่ายกว่าในการรวมท่อทั้งสอง$project
และ$match
:
db.T.aggregate([
{
"$project": {
"isGrade1Greater": { "$cmp": [ "$Grade1", "$Grade2" ] },
"Grade1": 1,
"Grade2": 1,
"OtherFields": 1,
...
}
},
{ "$match": { "isGrade1Greater": 1 } }
])
ด้วยMongoDB 3.4และใหม่กว่า:
db.T.aggregate([
{
"$addFields": {
"isGrade1Greater": { "$cmp": [ "$Grade1", "$Grade2" ] }
}
},
{ "$match": { "isGrade1Greater": 1 } }
])
ในกรณีที่ประสิทธิภาพมีความสำคัญมากกว่าความสามารถในการอ่านและตราบใดที่เงื่อนไขของคุณประกอบด้วยการคำนวณทางคณิตศาสตร์อย่างง่ายคุณสามารถใช้ไปป์ไลน์การรวมได้ ขั้นแรกให้ใช้ $ project เพื่อคำนวณด้านซ้ายมือของเงื่อนไข (นำฟิลด์ทั้งหมดไปทางซ้ายมือ) จากนั้นใช้ $ match เพื่อเปรียบเทียบกับค่าคงที่และตัวกรอง ด้วยวิธีนี้คุณจะหลีกเลี่ยงการเรียกใช้จาวาสคริปต์ ด้านล่างนี้คือการทดสอบของฉันใน python:
import pymongo
from random import randrange
docs = [{'Grade1': randrange(10), 'Grade2': randrange(10)} for __ in range(100000)]
coll = pymongo.MongoClient().test_db.grades
coll.insert_many(docs)
ใช้การรวม:
%timeit -n1 -r1 list(coll.aggregate([
{
'$project': {
'diff': {'$subtract': ['$Grade1', '$Grade2']},
'Grade1': 1,
'Grade2': 1
}
},
{
'$match': {'diff': {'$gt': 0}}
}
]))
1 ลูปที่ดีที่สุดคือ 1: 192 ms ต่อลูป
ใช้ find และ $ where:
%timeit -n1 -r1 list(coll.find({'$where': 'this.Grade1 > this.Grade2'}))
1 ลูปดีที่สุดคือ 1: 4.54 วินาทีต่อลูป