Memeriksa apakah bidang berisi string

454

Saya sedang mencari operator, yang memungkinkan saya untuk memeriksa, apakah nilai suatu bidang berisi string tertentu.

Sesuatu seperti:

db.users.findOne({$contains:{"username":"son"}})

Apakah itu mungkin?

johnny
sumber

Jawaban:

693

Anda dapat melakukannya dengan kode berikut.

db.users.findOne({"username" : {$regex : ".*son.*"}});
Parvin Gasimzade
sumber
16
Perhatikan bahwa ini tidak akan menggunakan indeks secara efisien dan menghasilkan semua nilai yang dipindai untuk kecocokan. Lihat catatan tentang Ekspresi Reguler
Stennie
7
@Tennie, lalu apa yang Anda sarankan untuk menggunakan indeks secara efisien dan menemukan substring.
Blue Sky
4
@Vish: jika kasus penggunaan umum Anda adalah pencarian teks-bebas dari suatu bidang dan Anda memiliki sejumlah besar dokumen, saya akan memberi token pada teks untuk pertanyaan yang lebih efisien. Anda bisa menggunakan multikeys untuk pencarian teks lengkap sederhana, atau mungkin membangun indeks terbalik sebagai koleksi terpisah. Untuk pencarian yang jarang atau koleksi kecil dokumen, pemindaian indeks lengkap mungkin kinerja yang dapat diterima (meskipun tidak optimal).
Stennie
98
Bukankah ini sedikit berlebihan? Yang Anda inginkan adalah db.users.findOne({"username" : {$regex : "son"}});
JamieJag
3
Mungkin ingin memeriksa pencarian teks lengkap dalam bahasa Mongo 2.6
wprl
179

Sebagai Mongo shell mendukung regex, itu sangat mungkin.

db.users.findOne({"username" : /.*son.*/});

Jika kami ingin kueri tidak peka huruf besar-kecil, kami dapat menggunakan opsi "i", seperti yang ditunjukkan di bawah ini:

db.users.findOne({"username" : /.*son.*/i});

Lihat: http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-RegularExpressions

James Gan
sumber
1
Harap sertakan cuplikan kode yang menunjukkan penggunaan ekspresi reguler untuk pencarian. Jawaban harus mencakup lebih banyak informasi daripada sekadar tautan ...
maerics
1
Jawaban yang dipilih tidak bekerja untuk saya, tetapi yang ini berhasil (saya mengeksekusi kuong mongo melalui perintah docker exec) Saya pikir yang ini harus menjadi jawaban yang dipilih karena tampaknya lebih fleksibel.
Arthur Weborg
5
seperti komentar dalam jawaban yang dipilih saya percaya db.users.findOne({"username" : /.*son.*/});juga bisa berlebihan dan regex bisa sederhana/son/
Arthur Weborg
2
Cara yang lebih ringkas daripada menggunakan $ regex
Lionet Chen
4
Sunting ini hanya menggunakan{ username: /son/ }
Wyck
150

https://docs.mongodb.com/manual/reference/sql-comparison/

http://php.net/manual/en/mongo.sqltomongo.php

MySQL

SELECT * FROM users WHERE username LIKE "%Son%"

MongoDB

db.users.find({username:/Son/})
Zheng Kai
sumber
8
Jawaban MongoDB Anda baik; pertimbangkan untuk mengedit pertanyaan Anda untuk menghapus saran MySQL yang tidak relevan.
maerics
31
Hapus semua permintaan atau ubah? SQL yang paling dikenal, sangat membantu untuk memahami MongoDB
Zheng Kai
4
@ZhengKai: di situs web ini Anda biasanya harus menjawab pertanyaan secara langsung, hanya menggunakan teknologi spesifik yang ditandai dan diminta.
maerics
98
@maerics secara pribadi saya menemukan bahwa Zheng memasukkan MySQL sangat berguna karena memberikan titik penyempurnaan.
Mike Bartlett
50
Saya juga menemukan referensi SQL yang relevan, saya pikir itu harus tetap.
vikingsteve
69

Pada versi 2.4, Anda dapat membuat indeks teks pada bidang untuk mencari dan menggunakan operator $ text untuk query.

Pertama, buat indeks:

db.users.createIndex( { "username": "text" } )

Lalu, untuk mencari:

db.users.find( { $text: { $search: "son" } } )

Benchmark (~ 150 ribu dokumen):

  • Regex (jawaban lain) => 5.6-6.9 detik
  • Pencarian Teks => .164-.201 detik

Catatan:

  • Koleksi hanya dapat memiliki satu indeks teks. Anda dapat menggunakan indeks teks wildcard jika Anda ingin mencari setiap lapangan string, seperti ini: db.collection.createIndex( { "$**": "text" } ).
  • Indeks teks bisa besar. Ini berisi satu entri indeks untuk setiap kata unik pasca-batang di setiap bidang yang diindeks untuk setiap dokumen yang dimasukkan.
  • Indeks teks akan membutuhkan waktu lebih lama untuk dibangun daripada indeks normal.
  • Indeks teks tidak menyimpan frasa atau informasi tentang kedekatan kata dalam dokumen. Hasilnya, kueri frasa akan berjalan jauh lebih efektif ketika seluruh koleksi sesuai dengan RAM.
okoboko
sumber
14
tidak, operator teks infact tidak mengizinkan untuk mengeksekusi "berisi", jadi itu hanya akan mengembalikan kecocokan kata yang tepat, satu-satunya pilihan saat ini pada 3.0 adalah menggunakan regex, yaitu db.users.find ({username: / son / i} ) yang satu ini mencari setiap pengguna yang mengandung "son" (case-insenstive)
comeGetSome
3
Apakah Anda harus mengindeks ulang ketika Anda menambah atau menghapus dokumen ke / dari koleksi?
Jake Wilson
Judul pertanyaan mengatakan "berisi". pencarian teks lengkap tidak berlaku untuk pertanyaan.
Donato
29

Karena ini adalah salah satu hit pertama di mesin pencari, dan tidak ada yang di atas tampaknya berfungsi untuk MongoDB 3.x, berikut adalah satu pencarian regex yang berfungsi:

db.users.find( { 'name' : { '$regex' : yourvalue, '$options' : 'i' } } )

Tidak perlu membuat dan indeks tambahan atau sama.

Nitai
sumber
1
Regex perlu disanitasi.
sean
16

Inilah yang harus Anda lakukan jika Anda menghubungkan MongoDB melalui Python

db.users.find({"username": {'$regex' : '.*' + 'Son' + '.*'}})

Anda juga dapat menggunakan nama variabel alih-alih 'Son' dan oleh karena itu penggabungan string.

Patthebug
sumber
di es2015 Anda dapat menggunakan backticks {$ regex: .*${value}.*}
Michael Guild
16

Cara termudah untuk menyelesaikan tugas ini

Jika Anda ingin kueri menjadi peka huruf besar-kecil

db.getCollection("users").find({'username':/Son/})

Jika Anda ingin kueri tidak peka huruf besar-kecil

db.getCollection("users").find({'username':/Son/i})
Anurag Misra
sumber
1
bagaimana cara menggunakan variabel dengan regex ??
Hisham
4

jawaban ideal indeks penggunaannya opsi i untuk case-sensitive

db.users.findOne({"username" : new RegExp(search_value, 'i') });
Hisyam
sumber
Regex perlu disanitasi.
sean
1

Cara mengabaikan tag HTML dalam kecocokan RegExp:

var text = '<p>The <b>tiger</b> (<i>Panthera tigris</i>) is the largest <a href="https://stackoverflow.com/wiki/Felidae" title="Felidae">cat</a> <a href="https://stackoverflow.com/wiki/Species" title="Species">species</a>, most recognizable for its pattern of dark vertical stripes on reddish-orange fur with a lighter underside. The species is classified in the genus <i><a href="https://stackoverflow.com/wiki/Panthera" title="Panthera">Panthera</a></i> with the <a href="https://stackoverflow.com/wiki/Lion" title="Lion">lion</a>, <a href="https://stackoverflow.com/wiki/Leopard" title="Leopard">leopard</a>, <a href="https://stackoverflow.com/wiki/Jaguar" title="Jaguar">jaguar</a>, and <a href="https://stackoverflow.com/wiki/Snow_leopard" title="Snow leopard">snow leopard</a>. It is an <a href="https://stackoverflow.com/wiki/Apex_predator" title="Apex predator">apex predator</a>, primarily preying on <a href="https://stackoverflow.com/wiki/Ungulate" title="Ungulate">ungulates</a> such as <a href="https://stackoverflow.com/wiki/Deer" title="Deer">deer</a> and <a href="https://stackoverflow.com/wiki/Bovid" class="mw-redirect" title="Bovid">bovids</a>.</p>';
var searchString = 'largest cat species';

var rx = '';
searchString.split(' ').forEach(e => {
  rx += '('+e+')((?:\\s*(?:<\/?\\w[^<>]*>)?\\s*)*)';
});

rx = new RegExp(rx, 'igm');

console.log(text.match(rx));

Ini mungkin sangat mudah untuk berubah menjadi filter agregasi MongoDB.

Tamás Polgár
sumber