MongoDB: เป็นไปได้หรือไม่ที่จะทำการสืบค้นแบบตรงตามตัวพิมพ์ใหญ่ - เล็ก?


304

ตัวอย่าง:

> db.stuff.save({"foo":"bar"});

> db.stuff.find({"foo":"bar"}).count();
1
> db.stuff.find({"foo":"BAR"}).count();
0

3
เนื่องจาก MongoDB 3.2 คุณสามารถทำการค้นหาด้วยตัวพิมพ์เล็กและตัวพิมพ์ใหญ่$caseSensitive: falseได้ ดู: docs.mongodb.org/manual/reference/operator/query/text/…
martin

4
โปรดทราบว่าที่อยู่ในดัชนีข้อความเท่านั้น
Willem D'Haeseleer

1
@martin: $caseSensitiveเป็นค่าเริ่มต้นที่เป็นเท็จอยู่แล้วและนั่นไม่ได้ตอบคำถามเพราะมันใช้ได้กับฟิลด์ที่จัดทำดัชนีเท่านั้น OP กำลังค้นหาการเปรียบเทียบสตริงที่ไม่ต้องคำนึงถึงตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก
Dan Dascalescu

คำตอบ:


343

คุณสามารถใช้regex

ในตัวอย่างของคุณที่จะ:

db.stuff.find( { foo: /^bar$/i } );

ฉันต้องบอกว่าบางทีคุณอาจจะลดราคา (หรือเพิ่มมูลค่า) ในแบบที่คุณทำแทนที่จะต้องเสียค่าใช้จ่ายเพิ่มเติมทุกครั้งที่คุณพบมัน เห็นได้ชัดว่าสิ่งนี้จะไม่ทำงานกับชื่อของผู้คนและเช่น แต่อาจใช้กรณีเช่นแท็ก


27
มันทำงานได้อย่างสมบูรณ์แบบ ทำให้มันทำงานใน PHP ด้วย: $ collection-> find (array ('key' => new MongoRegex ('/'.$ val.' / i ')));
ลุคเดนนิส

2
โดยเฉพาะอย่างยิ่งถ้าคุณกำลัง interpolating สตริง ({foo: / # {x} / i}) ที่อาจมีเครื่องหมายคำถามอยู่ในนั้น ..
ปีเตอร์ Ehrlich

17
อย่าลืม ^ และ $: MongoRegex ('/ ^'. preg_quote ($ val). '$ / i')
Julien

20
โปรดทราบว่าสิ่งนี้จะทำ fullscan แทนการใช้ดัชนี
Martin Konicek

12
มันจะไม่ทำแบบ fullscan ถ้าเขาใช้ ^ anchor ในตอนเริ่มต้นดังนั้นความสำคัญของคำแนะนำของ Julien
สันติภาพ

198

UPDATE:

คำตอบเดิมล้าสมัยแล้ว ตอนนี้ Mongodb รองรับการค้นหาข้อความขั้นสูงพร้อมคุณสมบัติมากมาย

คำตอบเดิม:

ควรสังเกตว่าการค้นหาด้วยตัวพิมพ์เล็กและตัวพิมพ์เล็กของ regex นั้นหมายความว่า mongodb ไม่สามารถค้นหาด้วยดัชนีดังนั้นการสืบค้นกับชุดข้อมูลขนาดใหญ่อาจใช้เวลานาน

แม้จะมีชุดข้อมูลขนาดเล็ก แต่ก็ไม่ค่อยมีประสิทธิภาพ คุณใช้ซีพียูที่มีขนาดใหญ่กว่าการรับประกันคิวรีของคุณซึ่งอาจกลายเป็นปัญหาหากคุณพยายามที่จะบรรลุระดับ

คุณสามารถจัดเก็บสำเนาตัวพิมพ์ใหญ่และค้นหาไฟล์นั้นได้ ตัวอย่างเช่นฉันมีตารางผู้ใช้ที่มีชื่อผู้ใช้ซึ่งเป็นตัวพิมพ์เล็ก แต่ ID เป็นสำเนาตัวพิมพ์ใหญ่ของชื่อผู้ใช้ สิ่งนี้ทำให้มั่นใจได้ว่าการทำสำเนาตามตัวพิมพ์เล็กและตัวพิมพ์ใหญ่นั้นเป็นไปไม่ได้ (การมีทั้ง "Foo" และ "foo" จะไม่ได้รับอนุญาต) และฉันสามารถค้นหาโดย id = username.toUpperCase () เพื่อค้นหาชื่อผู้ใช้

ถ้าเขตข้อมูลของคุณมีขนาดใหญ่เช่นเนื้อหาข้อความการทำสำเนาข้อมูลอาจไม่ใช่ตัวเลือกที่ดี ฉันเชื่อว่าการใช้ตัวทำดัชนีภายนอกเช่น Apache Lucene เป็นตัวเลือกที่ดีที่สุดในกรณีนี้


1
@Dan สำหรับข้อมูลใน MongoDB ล่าสุด "หากมีดัชนีสำหรับฟิลด์นั้น MongoDB จะจับคู่นิพจน์ทั่วไปกับค่าในดัชนีซึ่งอาจเร็วกว่าการสแกนคอลเลกชัน" - docs.mongodb.org/manual/reference/operator/query/regex/…
Sergiy Sokolenko

1
อาจมีการอัปเดตเอกสารแล้ว ตอนนี้พวกเขาพูดว่า "สำหรับเคียวรีนิพจน์ทั่วไปที่มีความละเอียดอ่อนหากมีดัชนีสำหรับฟิลด์แล้ว MongoDB จะจับคู่นิพจน์ปกติกับค่าในดัชนีซึ่งอาจเร็วกว่าการสแกนคอลเลกชัน"
Jeff Lewis

1
ข้อ จำกัด อื่นที่มีดัชนีข้อความคือคุณสามารถมีได้เพียงหนึ่งรายการต่อคอลเลกชัน (หลายคอลัมน์) ดังนั้นจึงไม่เหมาะถ้าคุณต้องการแยกการค้นหาในเขตข้อมูลที่แตกต่างกันสำหรับกรณีที่แตกต่างกัน
Paul Grimshaw

2
@SergiySokolenko: เอกสารตอนนี้พูดว่า (ย่อหน้าสุดท้ายในส่วน ): "เคียวรีนิพจน์ทั่วไปที่ไม่คำนึงถึงขนาดตัวพิมพ์ทั่วไปไม่สามารถใช้ดัชนีได้อย่างมีประสิทธิภาพการใช้งาน $ regex ไม่ได้คำนึงถึงการจัดเรียงและไม่สามารถใช้ดัชนี case-insensitive ได้"
Dan Dascalescu

1
โดยใช้การค้นหาข้อความแบบเต็มเป็นความผิดในกรณีนี้ (และอาจเป็นอันตราย ) เพราะคำถามคือเกี่ยวกับการทำแบบสอบถามกรณีตายเช่นusername: 'bill'การจับคู่BILLหรือBillไม่การค้นหาข้อความแบบเต็มซึ่งจะยังจับคู่เกิดคำพูดของbillเช่นBills, billedฯลฯ
แดนดาสคเลสุ

70

หากคุณต้องการสร้าง regexp จากตัวแปรนี่เป็นวิธีที่ดีกว่ามากในการทำ: https://stackoverflow.com/a/10728069/309514

จากนั้นคุณสามารถทำสิ่งที่ชอบ:

var string = "SomeStringToFind";
var regex = new RegExp(["^", string, "$"].join(""), "i");
// Creates a regex of: /^SomeStringToFind$/i
db.stuff.find( { foo: regex } );

สิ่งนี้มีประโยชน์ที่จะเป็นแบบโปรแกรมมากขึ้นหรือคุณสามารถเพิ่มประสิทธิภาพโดยการรวบรวมล่วงหน้าหากคุณนำมันกลับมาใช้ใหม่จำนวนมาก


1
new RegExp("^" + req.params.term.toLowerCase(), "i") ทำงานได้ดีเช่นกัน
Tahir Yasin

2
คุณควรพิจารณาที่จะหลีกเลี่ยงสตริงเพื่อเพิ่มความปลอดภัยหากตัวแปรนั้นมาจากคำขอ: stackoverflow.com/a/50633536/5195127
davidivad

เริ่มต้นด้วย MongoDB 3.4 มีการสนับสนุนแบบดั้งเดิมสำหรับดัชนีการตายของลูก
Dan Dascalescu

64

โปรดทราบว่าตัวอย่างก่อนหน้านี้:

db.stuff.find( { foo: /bar/i } );

จะทำให้ทุกรายการที่มีแถบตรงกับคำค้นหา (bar1, barxyz, openbar) มันอาจเป็นอันตรายมากสำหรับการค้นหาชื่อผู้ใช้ในฟังก์ชั่นรับรองความถูกต้อง ...

คุณอาจต้องทำให้ตรงกับคำค้นหาโดยใช้ไวยากรณ์ regexp ที่เหมาะสมเป็น:

db.stuff.find( { foo: /^bar$/i } );

ดูhttp://www.regular-expressions.info/สำหรับความช่วยเหลือด้านไวยากรณ์ของนิพจน์ทั่วไป


คำตอบนี้ดูเหมือนความคิดเห็น
Dan Dascalescu

62

เริ่มต้นด้วย MongoDB 3.4 วิธีที่แนะนำให้ดำเนินการค้นหากรณีตายอย่างรวดเร็วคือการใช้ดัชนีความรู้สึกกรณี

ฉันส่งอีเมลถึงผู้ก่อตั้งคนหนึ่งเพื่อโปรดให้ได้งานนี้และเขาทำให้มันเกิดขึ้น! มันเป็นปัญหาของ JIRA ตั้งแต่ปี 2009และหลายคนขอคุณลักษณะนี้ นี่คือวิธีการทำงาน:

ดัชนี case-insensitive ทำโดยระบุcollation ที่มีความแรง 1 หรือ 2 คุณสามารถสร้าง index case-insensitive index ดังนี้

db.cities.createIndex(
  { city: 1 },
  { 
    collation: {
      locale: 'en',
      strength: 2
    }
  }
);

คุณยังสามารถระบุการเรียงหน้าเริ่มต้นต่อการรวบรวมเมื่อคุณสร้างพวกเขา:

db.createCollection('cities', { collation: { locale: 'en', strength: 2 } } );

ในกรณีใดกรณีหนึ่งเพื่อใช้ดัชนี case-insensitive index คุณต้องระบุ collation เดียวกันในการfindดำเนินการที่ใช้เมื่อสร้างดัชนีหรือการรวบรวม:

db.cities.find(
  { city: 'new york' }
).collation(
  { locale: 'en', strength: 2 }
);

สิ่งนี้จะส่งคืน "นิวยอร์ก", "นิวยอร์ก", "นิวยอร์ก" ฯลฯ

บันทึกอื่น ๆ

  • คำตอบที่แนะนำให้ใช้การค้นหาข้อความแบบเต็มจะผิดในกรณีนี้ (และอาจเป็นอันตราย ) คำถามคือเกี่ยวกับการทำแบบสอบถามกรณีตายเช่นusername: 'bill'การจับคู่BILLหรือBillไม่ได้เป็นข้อความแบบเต็มคำค้นหาซึ่งจะยังจับคู่เกิดคำพูดของbillเช่นBills, billedฯลฯ
  • คำตอบแนะนำการใช้นิพจน์ปกติจะช้าเพราะแม้จะมีการจัดทำดัชนีที่รัฐเอกสาร :

    "โดยทั่วไปเคียวรีนิพจน์ที่คำนึงถึงขนาดตัวพิมพ์โดยทั่วไปจะไม่สามารถใช้ดัชนีได้อย่างมีประสิทธิภาพการใช้ $ regex ไม่ได้คำนึงถึงการจัดเรียงและไม่สามารถใช้ดัชนีที่ไม่คำนึงถึงขนาดตัวพิมพ์"

    $regexนอกจากนี้ยังมีคำตอบที่ใช้ความเสี่ยงของการฉีดเข้าของผู้ใช้


ทำงานได้ดีสำหรับฉันแม้จะมีการรวมท่อ
Morio

ฉันคิดว่านี่เป็นคำตอบที่ถูกต้องเพราะความเร็วในการอ่านข้อมูลมีความสำคัญ
Rndmax

ฉันไม่สามารถหาวิธีเพิ่มการเปรียบเทียบค่าเริ่มต้นในคอลเลกชันได้เมื่อสร้างขึ้นแล้ว มีวิธีการทำเช่นนั้น?
IncrediblePony

19
db.zipcodes.find({city : "NEW YORK"}); // Case-sensitive
db.zipcodes.find({city : /NEW york/i}); // Note the 'i' flag for case-insensitivity

1
@ OlegV.Volkov ต้องมีคำอธิบายเกี่ยวกับวิธีการที่คำตอบของคุณเหมาะสมและสิ่งที่ผิดในรหัสผู้ถาม
Parth Trivedi

1
คำตอบแบบรหัสเท่านั้นนี้จะไม่เพิ่มสิ่งใดไปยังคำตอบที่ยอมรับซึ่งโพสต์เมื่อ 6 ปีก่อน
Dan Dascalescu

19

TL; DR

วิธีที่ถูกต้องในการทำเช่นนี้ใน mongo

ห้ามใช้RegExp

เป็นไปตามธรรมชาติและใช้การสร้างดัชนี inbuilt ของ mongodb ค้นหา

ขั้นตอนที่ 1 :

db.articles.insert(
   [
     { _id: 1, subject: "coffee", author: "xyz", views: 50 },
     { _id: 2, subject: "Coffee Shopping", author: "efg", views: 5 },
     { _id: 3, subject: "Baking a cake", author: "abc", views: 90  },
     { _id: 4, subject: "baking", author: "xyz", views: 100 },
     { _id: 5, subject: "Café Con Leche", author: "abc", views: 200 },
     { _id: 6, subject: "Сырники", author: "jkl", views: 80 },
     { _id: 7, subject: "coffee and cream", author: "efg", views: 10 },
     { _id: 8, subject: "Cafe con Leche", author: "xyz", views: 10 }
   ]
)

ขั้นตอนที่ 2 :

จำเป็นต้องสร้างดัชนีในฟิลด์TEXTใดก็ตามที่คุณต้องการค้นหาโดยไม่ต้องมีการสืบค้นการทำดัชนีจะช้ามาก

db.articles.createIndex( { subject: "text" } )

ขั้นตอนที่ 3:

db.articles.find( { $text: { $search: "coffee",$caseSensitive :true } } )  //FOR SENSITIVITY
db.articles.find( { $text: { $search: "coffee",$caseSensitive :false } } ) //FOR INSENSITIVITY

1
ตัวเลือกที่ดี แต่ไม่มีอะไร "ถูกต้อง" มากขึ้นเกี่ยวกับการใช้ดัชนีข้อความเทียบกับ regex มันเป็นเพียงตัวเลือกอื่น มันมากเกินไปสำหรับกรณีของ OP
JohnnyHK

2
ยกเว้น regex ช้าลงอย่างมาก การค้นหาแบบเต็มข้อความก็ช้า แต่ก็ไม่ช้าเช่นกัน วิธีที่เร็วที่สุด (แต่บวมมากขึ้น) จะเป็นเขตข้อมูลแยกซึ่งตั้งค่าเป็นตัวพิมพ์เล็กเสมอ
Tom Mettam

4
โดยใช้การค้นหาข้อความแบบเต็มเป็นความผิดในกรณีนี้ (และอาจเป็นอันตราย ) เพราะคำถามคือเกี่ยวกับการทำแบบสอบถามกรณีตายเช่นusername: 'bill'การจับคู่BILLหรือBillไม่การค้นหาข้อความแบบเต็มซึ่งจะยังจับคู่เกิดคำพูดของbillเช่นBills, billedฯลฯ
แดนดาสคเลสุ

15
db.company_profile.find({ "companyName" : { "$regex" : "Nilesh" , "$options" : "i"}});

2
คุณเคยดูคำตอบที่มีอยู่ก่อนโพสต์นี้หรือไม่? แทนที่จะเป็นคำตอบเฉพาะรหัสที่ซ้ำกันเสมือนคุณอาจต้องการอธิบายวิธีเพิ่มมูลค่าบางอย่างเมื่อเทียบกับคำตอบก่อนหน้า
Dan Dascalescu

1
ฉันแค่ต้องการเพิ่มว่าคำตอบนี้คือสิ่งที่ทำให้ฉันได้รับการแก้ไข ฉันใช้กรอบงาน PHP และสิ่งนี้สอดคล้องกับไวยากรณ์ ORM ได้ดีในขณะที่โซลูชันอื่นที่นี่ไม่ได้ $existing = Users::masterFind('all', ['conditions' => ['traits.0.email' => ['$regex' => "^$value$", '$options' => 'i']]]);
Don Rzeszut

9

Mongo (รุ่นปัจจุบัน 2.0.0) ไม่อนุญาตให้มีการค้นหากรณีตายกับเขตข้อมูลการจัดทำดัชนี - ดูเอกสารของพวกเขา สำหรับเขตข้อมูลที่ไม่ได้จัดทำดัชนี regexes ที่ระบุไว้ในคำตอบอื่น ๆ ควรจะดี


19
เพียงเพื่อชี้แจงสิ่งนี้: การค้นหาแบบตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ได้รับอนุญาตในเขตข้อมูลที่จัดทำดัชนีพวกเขาจะไม่ใช้ดัชนีและจะช้าเช่นเดียวกับถ้าเขตข้อมูลไม่ได้จัดทำดัชนี
เฮฟวี 5

@ heavyi5ide เนื่องจากคำถามนี้ถูกใช้เพื่อทำเครื่องหมายรายการที่ซ้ำกันฉันคิดว่าฉันจะชี้แจงว่า regexes (จำเป็นสำหรับการค้นหาที่ไม่คำนึงถึงขนาดตัวพิมพ์) ใช้ดัชนีอย่างไรก็ตามพวกเขาต้องทำการสแกนดัชนีแบบเต็ม กล่าวอีกนัยหนึ่งพวกเขาไม่สามารถใช้ดัชนีได้อย่างมีประสิทธิภาพ โชคดีที่เอกสารได้รับการปรับปรุงตั้งแต่ 2011 แต่ก็ยังดีที่จะต้องทราบที่นี่เช่นกัน
Sammaye

7

สิ่งหนึ่งที่สำคัญมากที่ควรคำนึงถึงเมื่อใช้การสืบค้นแบบอิง Regex - เมื่อคุณทำสิ่งนี้กับระบบการเข้าสู่ระบบให้หลีกตัวละครทุกตัวที่คุณกำลังค้นหาและอย่าลืมตัวดำเนินการ ^ และ $ Lodash มีฟังก์ชั่นที่ดีสำหรับสิ่งนี้คุณควรจะใช้มันแล้ว:

db.stuff.find({$regex: new RegExp(_.escapeRegExp(bar), $options: 'i'})

ทำไม? ลองนึกภาพผู้ใช้ที่ป้อน.*เป็นชื่อผู้ใช้ของเขา นั่นจะตรงกับชื่อผู้ใช้ทั้งหมดเปิดใช้งานการเข้าสู่ระบบเพียงแค่เดารหัสผ่านของผู้ใช้


6

วิธีที่ดีที่สุดคือในภาษาที่คุณเลือกเมื่อสร้างโมเดล wrapper สำหรับวัตถุของคุณให้บันทึกของคุณ () วิธีการทำซ้ำผ่านชุดของเขตข้อมูลที่คุณจะค้นหาในที่มีการจัดทำดัชนีด้วย; ชุดของเขตข้อมูลเหล่านั้นควรมีลูกน้องตัวเล็กที่ใช้สำหรับการค้นหา

ทุกครั้งที่วัตถุถูกบันทึกอีกครั้งคุณสมบัติตัวพิมพ์เล็กจะถูกตรวจสอบและอัพเดตพร้อมกับการเปลี่ยนแปลงใด ๆ กับคุณสมบัติหลัก สิ่งนี้จะทำให้คุณสามารถค้นหาได้อย่างมีประสิทธิภาพ แต่ซ่อนงานพิเศษที่จำเป็นในการอัปเดตฟิลด์ lc ในแต่ละครั้ง

ฟิลด์ตัวพิมพ์เล็กอาจเป็นคีย์: ที่เก็บอ็อบเจ็กต์ค่าหรือเพียงชื่อฟิลด์ที่มีคำนำหน้า lc_ ฉันใช้อันที่สองเพื่อทำให้การสืบค้นง่ายขึ้น (การสืบค้นวัตถุที่ลึกอาจทำให้สับสนในบางครั้ง)

หมายเหตุ: คุณต้องการทำดัชนีฟิลด์ lc_ ไม่ใช่ฟิลด์หลักที่ใช้


วิธีแก้ปัญหาที่ดี แต่โชคดีที่เริ่มต้นด้วย MongoDB 3.4 มีการสนับสนุนดั้งเดิมสำหรับดัชนีการตายของลูกเล็ก
Dan Dascalescu

6

สมมติว่าคุณต้องการค้นหา "คอลัมน์" ใน "ตาราง" และคุณต้องการค้นหาแบบตรงตามตัวพิมพ์ใหญ่ - เล็ก วิธีที่ดีที่สุดและมีประสิทธิภาพมีดังต่อไปนี้

//create empty JSON Object
mycolumn = {};

//check if column has valid value
if(column) {
    mycolumn.column = {$regex: new RegExp(column), $options: "i"};
}
Table.find(mycolumn);

โค้ดด้านบนเพียงเพิ่มมูลค่าการค้นหาของคุณเป็น RegEx และค้นหาด้วยเกณฑ์ insensitve ที่ตั้งค่าด้วยตัวเลือก "i"

ทั้งหมดที่ดีที่สุด


5

การใช้พังพอนสิ่งนี้ได้ผลกับฉัน:

var find = function(username, next){
    User.find({'username': {$regex: new RegExp('^' + username, 'i')}}, function(err, res){
        if(err) throw err;
        next(null, res);
    });
}

8
ไม่ได้เป็น.toLowerCase()ที่ซ้ำซ้อนหากคุณได้ระบุธงกรณีตายของi?
k00k

ใช่แล้ว. คุณไม่ต้องการ. toLowerCase () ฉันลบมันออกจากคำตอบ
ChrisRich

อืมมันควรเป็นแบบนี้เหรอ? เมื่อฉันค้นหา "mark" มันจะได้รับทุก ๆ ระเบียนด้วย "marko" - มีวิธีเดียวที่จะไม่สนใจขนาดตัวพิมพ์
Suisse

ตกลงพบว่า regex ที่ถูกต้องจะเป็น: '^' + serach_name + '$', "i"
Suisse

3
นี่คืออันตราย คุณไม่ได้หลบหนีชื่อผู้ใช้ดังนั้นการฉีด regex ใดก็ได้สามารถทำได้
Tom Mettam

3

กรอบการรวมถูกนำเสนอใน MongoDB 2.2 คุณสามารถใช้ตัวดำเนินการสตริง "$ strcasecmp" เพื่อทำการเปรียบเทียบแบบตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ระหว่างสตริง แนะนำให้มากกว่าและง่ายกว่าการใช้ regex

นี่เป็นเอกสารอย่างเป็นทางการกับผู้ประกอบการรวมคำสั่ง: https://docs.mongodb.com/manual/reference/operator/aggregation/strcasecmp/#exp._S_strcasecmp


4
วิธีการใช้สิ่งนี้ในการค้นหา () แบบสอบถาม? db.stuff.find ({name: $ strcasecmp (name)})?
Suisse

3

คุณสามารถใช้Case Insensitive Index :

ตัวอย่างต่อไปนี้สร้างคอลเลกชันที่ไม่มีการเปรียบเทียบค่าเริ่มต้นจากนั้นเพิ่มดัชนีในฟิลด์ชื่อด้วยการเปรียบเทียบแบบตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ ส่วนประกอบระหว่างประเทศสำหรับ Unicode

/* strength: CollationStrength.Secondary
* Secondary level of comparison. Collation performs comparisons up to secondary * differences, such as diacritics. That is, collation performs comparisons of 
* base characters (primary differences) and diacritics (secondary differences). * Differences between base characters takes precedence over secondary 
* differences.
*/
db.users.createIndex( { name: 1 }, collation: { locale: 'tr', strength: 2 } } )

ในการใช้ดัชนีแบบสอบถามต้องระบุการเปรียบเทียบเดียวกัน

db.users.insert( [ { name: "Oğuz" },
                            { name: "oğuz" },
                            { name: "OĞUZ" } ] )

// does not use index, finds one result
db.users.find( { name: "oğuz" } )

// uses the index, finds three results
db.users.find( { name: "oğuz" } ).collation( { locale: 'tr', strength: 2 } )

// does not use the index, finds three results (different strength)
db.users.find( { name: "oğuz" } ).collation( { locale: 'tr', strength: 1 } )

หรือคุณสามารถสร้างคอลเลกชันที่มีการเรียงหน้าเริ่มต้น:

db.createCollection("users", { collation: { locale: 'tr', strength: 2 } } )
db.users.createIndex( { name : 1 } ) // inherits the default collation

ดูเหมือนว่ามีปัญหาด้านไวยากรณ์เล็กน้อย (ไม่มีเครื่องหมายปีกกา) โปรดอัปเดตข้อความค้นหา: db.users.createIndex( { name: 1 }, {collation: { locale: 'tr', strength: 2 } } )
Mohd Belal

3

สำหรับการค้นหาตัวแปรและหลบหนีมัน:

const escapeStringRegexp = require('escape-string-regexp')
const name = 'foo'
db.stuff.find({name: new RegExp('^' + escapeStringRegexp(name) + '$', 'i')})   

การหลีกเลี่ยงตัวแปรจะช่วยป้องกันเคียวรีจากการโจมตีด้วย '. *' หรือ regex อื่น ๆ

หลบหนีสตริง regexp


1

ใช้RegExpในกรณีที่ตัวเลือกอื่น ๆ ใช้ไม่ได้ RegExp เป็นตัวเลือกที่ดี ทำให้สตริงตัวพิมพ์เล็กและตัวพิมพ์เล็ก

var username = new RegExp("^" + "John" + "$", "i");;

ใช้ชื่อผู้ใช้ในแบบสอบถามแล้วทำมัน

ฉันหวังว่ามันจะทำงานให้คุณเช่นกัน ทั้งหมดที่ดีที่สุด


0

ฉันได้สร้าง Func ง่าย ๆ สำหรับ case insensitive regex ซึ่งฉันใช้ในตัวกรองของฉัน

private Func<string, BsonRegularExpression> CaseInsensitiveCompare = (field) => 
            BsonRegularExpression.Create(new Regex(field, RegexOptions.IgnoreCase));

จากนั้นคุณก็กรองลงในเขตข้อมูลดังนี้

db.stuff.find({"foo": CaseInsensitiveCompare("bar")}).count();

0

การใช้ตัวกรองใช้งานได้สำหรับฉันใน C #

string s = "searchTerm";
    var filter = Builders<Model>.Filter.Where(p => p.Title.ToLower().Contains(s.ToLower()));
                var listSorted = collection.Find(filter).ToList();
                var list = collection.Find(filter).ToList();

มันอาจใช้ดัชนีเพราะฉันเชื่อว่าวิธีการนั้นถูกเรียกหลังจากการส่งคืนเกิดขึ้น แต่ฉันยังไม่ได้ทดสอบสิ่งนี้

นอกจากนี้ยังหลีกเลี่ยงปัญหา

var filter = Builders<Model>.Filter.Eq(p => p.Title.ToLower(), s.ToLower());

mongodb นั้นจะคิดว่า p.Title.ToLower () เป็นคุณสมบัติและแผนที่ไม่ถูกต้อง


ขอบคุณมันใช้งานได้สำหรับฉัน ที่นี่เราจำเป็นต้องได้รับตัวกรองในตัวแปรแล้วส่งผ่านวิธีการค้นหา ()
Nilay

0

สำหรับคนใดคนหนึ่งโดยใช้ golang และความปรารถนาที่จะมีกรณีการค้นหาข้อความที่มีความสำคัญที่เต็มไปด้วย MongoDB และ mgo godoc GlobalSign ห้องสมุด

collation := &mgo.Collation{
    Locale:   "en",
    Strength: 2, 
}


err := collection.Find(query).Collation(collation)

-1

อย่างที่คุณเห็นใน mongo docs - เนื่องจาก$textดัชนีรุ่น 3.2 ไม่คำนึงถึงตัวพิมพ์ใหญ่และตัวพิมพ์เล็กตามค่าเริ่มต้น: https://docs.mongodb.com/manual/core/index-text/#text-index-case-insensitivity

สร้างดัชนีข้อความและใช้ประกอบข้อความ $ ในการค้นหาของคุณ


โดยใช้การค้นหาข้อความแบบเต็มเป็นความผิดในกรณีนี้ (และอาจเป็นอันตราย ) เพราะคำถามคือเกี่ยวกับการทำแบบสอบถามกรณีตายเช่นusername: 'bill'การจับคู่BILLหรือBillไม่การค้นหาข้อความแบบเต็มซึ่งจะยังจับคู่เกิดคำพูดของbillเช่นBills, billedฯลฯ
แดนดาสคเลสุ

-1

สิ่งเหล่านี้ได้รับการทดสอบสำหรับการค้นหาสตริง

{'_id': /.*CM.*/}               ||find _id where _id contains   ->CM
{'_id': /^CM/}                  ||find _id where _id starts     ->CM
{'_id': /CM$/}                  ||find _id where _id ends       ->CM

{'_id': /.*UcM075237.*/i}       ||find _id where _id contains   ->UcM075237, ignore upper/lower case
{'_id': /^UcM075237/i}          ||find _id where _id starts     ->UcM075237, ignore upper/lower case
{'_id': /UcM075237$/i}          ||find _id where _id ends       ->UcM075237, ignore upper/lower case

-1

ฉันพบปัญหาที่คล้ายกันและนี่คือสิ่งที่ได้ผลสำหรับฉัน

  const flavorExists = await Flavors.findOne({
    'flavor.name': { $regex: flavorName, $options: 'i' },
  });

วิธีแก้ปัญหานี้เคยให้มาสองครั้งแล้ว โปรดตรวจสอบคำตอบที่มีอยู่ก่อนโพสต์ใหม่
Dan Dascalescu

@DanDascalescu ไม่แน่ใจว่าสิ่งที่คุณกำลังพูดถึงเมื่อ CTRL + F โซลูชั่นที่คล้ายกันกับ upvotes จำนวนมากโพสต์เมื่อกันยายน 2018 ฉันโพสต์คำตอบของฉันเมษายน 2018 ฉันโพสต์คำตอบนี้เพราะไม่มีในเวลานั้น โปรดตรวจสอบเมื่อมีการโพสต์ก่อนเตือนผู้ที่พยายามจะช่วยอย่างแท้จริง
Woppi

ผมกำลังพูดถึงคำตอบนี้ตั้งแต่เดือนเมษายนปี 2016 และคำตอบนี้ตั้งแต่เดือนพฤษภาคมปี 2016 ทั้งการใช้งานและ$regex $optionsคุณ Ctrl + F ทำอะไร
Dan Dascalescu

นอกจากนี้การใช้$regexไม่มีประสิทธิภาพและอาจไม่ปลอดภัยอย่างที่ฉันได้อธิบายไว้ในการแก้ไขคำตอบสำหรับปี 2559นี้ ไม่มีความละอายในการลบคำตอบหากไม่ให้บริการชุมชนอีกต่อไป!
Dan Dascalescu

ตั้งข้อสังเกตกับ $ regex ที่ไม่มีประสิทธิภาพขอบคุณมาก ฉัน Ctrl + F $ ตัวเลือก เราเป็นเพียงสองที่นี่โดยไม่มี Regexp ใหม่ในรหัส $ regex ของเราเมษายน 2018 และ Sep 2018 ฉันไม่ได้ใช้ Regexp ใหม่ในคำตอบของฉัน ฉันลืมปัญหาเฉพาะที่ฉันมีกับ Regexp ใหม่ที่ได้รับการแก้ไขเมื่อฉันลบออกและใช้โซลูชันนี้ที่ฉันโพสต์แทน
Woppi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.