Tìm kiếm mongodb hoạt động như thế nào?

Phương thức

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
2 được sử dụng để thực hiện các truy vấn trong MongoDB. Truy vấn trả về một tập hợp con các tài liệu trong một bộ sưu tập, từ không có tài liệu nào đến toàn bộ bộ sưu tập. Tài liệu nào được trả về được xác định bởi đối số đầu tiên của
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
2, đây là tài liệu chỉ định tiêu chí truy vấn

Một tài liệu truy vấn trống (tôi. e. ,

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
4) khớp với mọi thứ trong bộ sưu tập. Nếu
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
2 không được cung cấp một tài liệu truy vấn, nó sẽ mặc định là
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
4. Ví dụ, sau đây

> db.c.find()

khớp với mọi tài liệu trong bộ sưu tập c (và trả về các tài liệu này theo lô)

Khi chúng tôi bắt đầu thêm các cặp khóa/giá trị vào tài liệu truy vấn, chúng tôi bắt đầu hạn chế tìm kiếm của mình. Điều này hoạt động một cách đơn giản cho hầu hết các loại. số khớp với số, booleans khớp với booleans và chuỗi khớp với chuỗi. Truy vấn một loại đơn giản dễ dàng như chỉ định giá trị mà bạn đang tìm kiếm. Ví dụ: để tìm tất cả các tài liệu có giá trị cho

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
7 là 27, chúng ta có thể thêm cặp khóa/giá trị đó vào tài liệu truy vấn

> db.users.find({"age" : 27})

Nếu chúng ta có một chuỗi mà chúng ta muốn so khớp, chẳng hạn như khóa

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
8 với giá trị
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
9, thì chúng ta sẽ sử dụng cặp khóa/giá trị đó để thay thế

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
0

Nhiều điều kiện có thể được xâu chuỗi lại với nhau bằng cách thêm nhiều cặp khóa/giá trị hơn vào tài liệu truy vấn, điều này được hiểu là “

> db.users.find({"age" : 27})
00 AND
> db.users.find({"age" : 27})
01 AND … AND
> db.users.find({"age" : 27})
02. ” Chẳng hạn, để có được tất cả người dùng 27 tuổi với tên người dùng “joe”, chúng tôi có thể truy vấn như sau

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
4

Chỉ định phím nào sẽ trả về

Đôi khi bạn không cần trả về tất cả các cặp khóa/giá trị trong tài liệu. Nếu trường hợp này xảy ra, bạn có thể chuyển đối số thứ hai tới

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
2 (hoặc
> db.users.find({"age" : 27})
04) chỉ định các khóa bạn muốn. Điều này làm giảm cả lượng dữ liệu được gửi qua dây cũng như thời gian và bộ nhớ được sử dụng để giải mã tài liệu ở phía máy khách

Ví dụ: nếu bạn có một bộ sưu tập người dùng và bạn chỉ quan tâm đến các khóa

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
8 và
> db.users.find({"age" : 27})
06, bạn chỉ có thể trả lại các khóa đó bằng truy vấn sau

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
9

Như bạn có thể thấy từ đầu ra trước đó, khóa

> db.users.find({"age" : 27})
07 được trả về theo mặc định, ngay cả khi nó không được yêu cầu cụ thể

Bạn cũng có thể sử dụng tham số thứ hai này để loại trừ các cặp khóa/giá trị cụ thể khỏi kết quả của truy vấn. Chẳng hạn, bạn có thể có các tài liệu có nhiều khóa khác nhau và điều duy nhất bạn biết là bạn không bao giờ muốn trả lại khóa

> db.users.find({"age" : 27})
08

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
2

Điều này cũng có thể ngăn chặn việc trả lại

> db.users.find({"age" : 27})
07

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
4

Có một số hạn chế đối với truy vấn. Giá trị của tài liệu truy vấn phải là một hằng số đối với cơ sở dữ liệu. (Nó có thể là một biến bình thường trong mã của riêng bạn. ) Tức là nó không thể tham chiếu đến giá trị của một khóa khác trong tài liệu. Ví dụ: nếu chúng tôi đang giữ khoảng không quảng cáo và chúng tôi có cả khóa

> db.users.find({"age" : 27})
10 và
> db.users.find({"age" : 27})
11, thì chúng tôi không thể so sánh giá trị của chúng bằng cách truy vấn như sau

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
7

Có nhiều cách để làm điều này (xem $where Queries), nhưng bạn thường sẽ có hiệu suất tốt hơn bằng cách cấu trúc lại tài liệu của mình một chút, sao cho một truy vấn "bình thường" là đủ. Trong ví dụ này, thay vào đó, chúng ta có thể sử dụng các phím

> db.users.find({"age" : 27})
12 và
> db.users.find({"age" : 27})
10. Sau đó, mỗi khi ai đó mua một mặt hàng, chúng tôi sẽ giảm giá trị của khóa
> db.users.find({"age" : 27})
10 xuống một. Cuối cùng, chúng ta có thể thực hiện một truy vấn đơn giản để kiểm tra mặt hàng nào đã hết hàng

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
1

Các truy vấn có thể vượt ra ngoài kết hợp chính xác được mô tả trong phần trước;

> db.users.find({"age" : 27})
15,
> db.users.find({"age" : 27})
16,
> db.users.find({"age" : 27})
17, and
> db.users.find({"age" : 27})
18 are all comparison operators, corresponding to <, <=, >, and >=, respectively. They can be combined to look for a range of values. For example, to look for users who are between the ages of 18 and 30, we can do this:

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})

Điều này sẽ tìm thấy tất cả các tài liệu trong đó trường "

> db.users.find({"age" : 27})
19" lớn hơn hoặc bằng 18 VÀ nhỏ hơn hoặc bằng 30

Các loại truy vấn phạm vi này thường hữu ích cho các ngày. Ví dụ để tìm những người đăng ký trước 01/01/2007 ta có thể làm như sau

> db.users.find({"age" : 27})
0

Đối sánh chính xác vào một ngày ít hữu ích hơn vì ngày chỉ được lưu trữ với độ chính xác đến mili giây. Thường thì bạn muốn có cả ngày, tuần hoặc tháng, nên cần phải thực hiện một truy vấn phạm vi

Để truy vấn các tài liệu mà giá trị của khóa không bằng một giá trị nhất định, bạn phải sử dụng một toán tử điều kiện khác,

> db.users.find({"age" : 27})
20, viết tắt của “không bằng. ” Nếu bạn muốn tìm tất cả người dùng không có tên người dùng là “joe”, bạn có thể truy vấn họ bằng cách này

> db.users.find({"age" : 27})
1

> db.users.find({"age" : 27})
20 có thể được sử dụng với bất kỳ loại nào

Có hai cách để thực hiện truy vấn OR trong MongoDB.

> db.users.find({"age" : 27})
22 có thể được sử dụng để truy vấn nhiều giá trị khác nhau cho một khóa.
> db.users.find({"age" : 27})
23 tổng quát hơn;

Nếu bạn có nhiều giá trị có thể khớp với một khóa, hãy sử dụng một loạt tiêu chí với

> db.users.find({"age" : 27})
22. Chẳng hạn, giả sử chúng ta đang tổ chức một cuộc xổ số và vé số trúng thưởng là 725, 542 và 390. Để tìm cả ba tài liệu này, chúng ta có thể xây dựng truy vấn sau

> db.users.find({"age" : 27})
2

> db.users.find({"age" : 27})
22 rất linh hoạt và cho phép bạn chỉ định các tiêu chí thuộc các loại cũng như giá trị khác nhau. Ví dụ: nếu chúng tôi đang dần di chuyển lược đồ của mình để sử dụng tên người dùng thay vì số ID người dùng, chúng tôi có thể truy vấn một trong hai bằng cách sử dụng

> db.users.find({"age" : 27})
3

Điều này phù hợp với các tài liệu có

> db.users.find({"age" : 27})
26 bằng 12345 và các tài liệu có
> db.users.find({"age" : 27})
26 bằng
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
9

Nếu

> db.users.find({"age" : 27})
22 được cung cấp một mảng có một giá trị, nó sẽ hoạt động giống như khớp trực tiếp với giá trị. Chẳng hạn,
> db.users.find({"age" : 27})
30 khớp với các tài liệu giống như
> db.users.find({"age" : 27})
31

Ngược lại với

> db.users.find({"age" : 27})
22 là
> db.users.find({"age" : 27})
33, trả về các tài liệu không khớp với bất kỳ tiêu chí nào trong mảng. Nếu chúng tôi muốn trả lại tất cả những người không giành được bất cứ thứ gì trong xổ số, chúng tôi có thể truy vấn họ bằng cách này

> db.users.find({"age" : 27})
4

Truy vấn này trả về tất cả những người không có vé với những con số đó

> db.users.find({"age" : 27})
22 cung cấp cho bạn truy vấn OR cho một khóa duy nhất, nhưng nếu chúng tôi cần tìm tài liệu trong đó
> db.users.find({"age" : 27})
35 là 725 hoặc
> db.users.find({"age" : 27})
36 là
> db.users.find({"age" : 27})
37 thì sao? .
> db.users.find({"age" : 27})
23 có một loạt các tiêu chí có thể. Trong trường hợp xổ số, sử dụng
> db.users.find({"age" : 27})
23 sẽ như thế này

> db.users.find({"age" : 27})
5

> db.users.find({"age" : 27})
23 có thể chứa các điều kiện khác. Ví dụ: nếu chúng tôi muốn khớp bất kỳ giá trị nào trong ba giá trị
> db.users.find({"age" : 27})
35 hoặc khóa
> db.users.find({"age" : 27})
36, chúng tôi có thể sử dụng giá trị này

> db.users.find({"age" : 27})
6

Với truy vấn loại AND thông thường, bạn muốn thu hẹp kết quả của mình càng nhiều càng tốt trong càng ít đối số càng tốt. Truy vấn loại OR thì ngược lại. chúng hiệu quả nhất nếu các đối số đầu tiên khớp với càng nhiều tài liệu càng tốt

Mặc dù

> db.users.find({"age" : 27})
23 sẽ luôn hoạt động, hãy sử dụng
> db.users.find({"age" : 27})
22 bất cứ khi nào có thể vì trình tối ưu hóa truy vấn sẽ xử lý nó hiệu quả hơn

> db.users.find({"age" : 27})
46 là một siêu điều kiện. nó có thể được áp dụng trên bất kỳ tiêu chí nào khác. Ví dụ, hãy xem xét toán tử mô đun,
> db.users.find({"age" : 27})
47.
> db.users.find({"age" : 27})
47 truy vấn cho các khóa có giá trị, khi chia cho giá trị đầu tiên đã cho, có phần còn lại là giá trị thứ hai

> db.users.find({"age" : 27})
7

Truy vấn trước đó trả về những người dùng có

> db.users.find({"age" : 27})
49 là 1, 6, 11, 16, v.v. Thay vào đó, nếu chúng tôi muốn trả lại người dùng có
> db.users.find({"age" : 27})
49 là 2, 3, 4, 5, 7, 8, 9, 10, 12, v.v. , chúng ta có thể sử dụng
> db.users.find({"age" : 27})
46

> db.users.find({"age" : 27})
8

> db.users.find({"age" : 27})
46 có thể đặc biệt hữu ích khi kết hợp với các biểu thức chính quy để tìm tất cả các tài liệu không khớp với một mẫu nhất định (cách sử dụng biểu thức chính quy được mô tả trong phần Biểu thức chính quy)

Nếu bạn xem các công cụ sửa đổi cập nhật trong chương trước và các tài liệu truy vấn trước đó, bạn sẽ nhận thấy rằng các khóa có tiền tố $ nằm ở các vị trí khác nhau. Trong truy vấn,

> db.users.find({"age" : 27})
15 nằm trong tài liệu bên trong; . Điều này thường đúng. điều kiện là khóa tài liệu bên trong và công cụ sửa đổi luôn là khóa trong tài liệu bên ngoài

Nhiều điều kiện có thể được đặt trên một phím duy nhất. Ví dụ: để tìm tất cả người dùng trong độ tuổi từ 20 đến 30, chúng tôi có thể truy vấn cả

> db.users.find({"age" : 27})
17 và
> db.users.find({"age" : 27})
15 trên khóa
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
7

> db.users.find({"age" : 27})
9

Bất kỳ số lượng điều kiện nào cũng có thể được sử dụng với một phím duy nhất. Tuy nhiên, không thể sử dụng nhiều công cụ sửa đổi cập nhật trên một phím. Ví dụ: bạn không thể có tài liệu sửa đổi chẳng hạn như

> db.users.find({"age" : 27})
58 vì nó sửa đổi
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
7 hai lần. Với điều kiện truy vấn, không áp dụng quy tắc như vậy

Có một số "toán tử meta" có trong tài liệu bên ngoài. "______760“, "______761“, và "

> db.users.find({"age" : 27})
62“. Chúng đều có hình thức giống nhau

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
00

Truy vấn này sẽ khớp với các tài liệu có trường "

> db.users.find({"age" : 27})
63" vừa nhỏ hơn 1 vừa bằng 4. Mặc dù đây có vẻ là những điều kiện trái ngược nhau, nhưng vẫn có thể đáp ứng nếu trường "
> db.users.find({"age" : 27})
63" là một mảng.
> db.users.find({"age" : 27})
65 sẽ phù hợp. Lưu ý rằng trình tối ưu hóa truy vấn không tối ưu hóa "______760" cũng như các toán tử khác. Truy vấn này sẽ hiệu quả hơn để cấu trúc như

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
01

Như đã đề cập trong Chương 2, MongoDB có nhiều loại có thể được sử dụng trong tài liệu. Một số loại này có hành vi đặc biệt khi truy vấn

> db.users.find({"age" : 27})
67 cư xử hơi lạ. Nó khớp với chính nó, vì vậy nếu chúng tôi có một bộ sưu tập với các tài liệu sau

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
02

chúng tôi có thể truy vấn các tài liệu có khóa

> db.users.find({"age" : 27})
68 là
> db.users.find({"age" : 27})
67 theo cách mong đợi

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
03

Tuy nhiên,

> db.users.find({"age" : 27})
67 không chỉ khớp với chính nó mà còn khớp với “không tồn tại. ” Như vậy, truy vấn khóa có giá trị
> db.users.find({"age" : 27})
67 sẽ trả về tất cả các tài liệu thiếu khóa đó

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
04

Nếu chúng tôi chỉ muốn tìm các khóa có giá trị là

> db.users.find({"age" : 27})
67, chúng tôi có thể kiểm tra xem khóa đó có phải là
> db.users.find({"age" : 27})
67 hay không bằng cách sử dụng điều kiện
> db.users.find({"age" : 27})
74

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
05

Thật không may, không có toán tử

> db.users.find({"age" : 27})
75, điều này khiến điều này hơi khó xử, nhưng
> db.users.find({"age" : 27})
22 với một phần tử là tương đương

Biểu thức chính quy rất hữu ích để khớp chuỗi linh hoạt. Ví dụ: nếu chúng tôi muốn tìm tất cả người dùng có tên Joe hoặc joe, chúng tôi có thể sử dụng biểu thức chính quy để thực hiện khớp không phân biệt chữ hoa chữ thường

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
06

Cờ biểu thức chính quy (ví dụ:

> db.users.find({"age" : 27})
77) được cho phép nhưng không bắt buộc. Nếu chúng tôi muốn khớp không chỉ các cách viết hoa khác nhau của joe mà còn cả joey, chúng tôi có thể tiếp tục cải thiện biểu thức chính quy của mình

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
07

MongoDB sử dụng thư viện Biểu thức chính quy tương thích (PCRE) Perl để khớp với các biểu thức chính quy; . Bạn nên kiểm tra cú pháp của mình bằng trình bao JavaScript trước khi sử dụng nó trong truy vấn để đảm bảo cú pháp khớp với những gì bạn cho là khớp

Ghi chú

MongoDB có thể tận dụng một chỉ mục cho các truy vấn trên các biểu thức chính quy tiền tố (e. g. ,

> db.users.find({"age" : 27})
78). Chỉ mục không thể được sử dụng cho các tìm kiếm không phân biệt chữ hoa chữ thường (
> db.users.find({"age" : 27})
79)

Cụm từ thông dụng cũng có thể khớp với chính chúng. Rất ít người chèn biểu thức chính quy vào cơ sở dữ liệu, nhưng nếu bạn chèn một cái, bạn có thể khớp nó với chính nó

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
08

Truy vấn các phần tử của một mảng được thiết kế để hoạt động theo cách truy vấn các đại lượng vô hướng. Ví dụ, nếu mảng là một danh sách các loại trái cây, như thế này

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
09

truy vấn sau

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
40

sẽ khớp thành công tài liệu. Chúng tôi có thể truy vấn nó theo cách tương tự như khi chúng tôi có một tài liệu trông giống như tài liệu (bất hợp pháp).

> db.users.find({"age" : 27})
80

Nếu bạn cần khớp các mảng theo nhiều hơn một phần tử, bạn có thể sử dụng

> db.users.find({"age" : 27})
81. Điều này cho phép bạn khớp danh sách các phần tử. Ví dụ: giả sử chúng tôi đã tạo một bộ sưu tập có ba phần tử

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
41

Sau đó, chúng tôi có thể tìm thấy tất cả các tài liệu có cả hai yếu tố

> db.users.find({"age" : 27})
82 và
> db.users.find({"age" : 27})
83 bằng cách truy vấn với
> db.users.find({"age" : 27})
81

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
42

Thứ tự không quan trọng. Lưu ý

> db.users.find({"age" : 27})
83 xuất hiện trước
> db.users.find({"age" : 27})
82 trong kết quả thứ hai. Sử dụng mảng một phần tử với
> db.users.find({"age" : 27})
81 tương đương với việc không sử dụng
> db.users.find({"age" : 27})
81. Chẳng hạn,
> db.users.find({"age" : 27})
89 sẽ khớp với các tài liệu giống như
> db.users.find({"age" : 27})
90

Bạn cũng có thể truy vấn bằng cách khớp chính xác bằng cách sử dụng toàn bộ mảng. Tuy nhiên, đối sánh chính xác sẽ không khớp với tài liệu nếu thiếu hoặc thừa bất kỳ thành phần nào. Ví dụ: điều này sẽ khớp với tài liệu đầu tiên ở trên

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
43

Nhưng điều này sẽ không

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
44

và điều này cũng sẽ không

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
45

Nếu bạn muốn truy vấn một phần tử cụ thể của một mảng, bạn có thể chỉ định một chỉ mục bằng cú pháp

> db.users.find({"age" : 27})
91.
> db.users.find({"age" : 27})
92

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
46

Mảng luôn được lập chỉ mục 0, vì vậy điều này sẽ khớp phần tử mảng thứ ba với chuỗi

> db.users.find({"age" : 27})
93

Một điều kiện hữu ích để truy vấn mảng là

> db.users.find({"age" : 27})
94, cho phép bạn truy vấn các mảng có kích thước nhất định. Đây là một ví dụ

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
47

Một truy vấn phổ biến là lấy một loạt các kích cỡ. Không thể kết hợp

> db.users.find({"age" : 27})
94 với một điều kiện $ khác (trong ví dụ này là
> db.users.find({"age" : 27})
17), nhưng truy vấn này có thể được thực hiện bằng cách thêm khóa
> db.users.find({"age" : 27})
97 vào tài liệu. Sau đó, mỗi khi bạn thêm một phần tử vào mảng, hãy tăng giá trị của
> db.users.find({"age" : 27})
97. Nếu bản cập nhật ban đầu trông như thế này

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
48

nó có thể được thay đổi thành cái này

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
49

Gia tăng cực kỳ nhanh, vì vậy mọi hình phạt về hiệu suất đều không đáng kể. Lưu trữ các tài liệu như thế này cho phép bạn thực hiện các truy vấn như thế này

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
90

Thật không may, kỹ thuật này không hoạt động tốt với toán tử

> db.users.find({"age" : 27})
99

Như đã đề cập trước đó trong chương này, đối số thứ hai tùy chọn cho

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
2 chỉ định các khóa được trả về. Toán tử đặc biệt
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
001 có thể được sử dụng để trả về một tập hợp con các phần tử cho một khóa mảng

Ví dụ: giả sử chúng tôi có một tài liệu về bài đăng trên blog và chúng tôi muốn trả lại 10 nhận xét đầu tiên

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
91

Ngoài ra, nếu chúng tôi muốn 10 nhận xét cuối cùng, chúng tôi có thể sử dụng −10

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
92

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
001 cũng có thể trả về các trang ở giữa kết quả bằng cách lấy phần bù và số phần tử cần trả về

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
93

Điều này sẽ bỏ qua 23 phần tử đầu tiên và trả về phần tử thứ 24 đến thứ 33. Nếu có ít hơn 33 phần tử trong mảng, nó sẽ trả về càng nhiều càng tốt

Trừ khi có quy định khác, tất cả các khóa trong tài liệu được trả về khi sử dụng

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
001. Điều này không giống như các trình xác định khóa khác, ngăn chặn các khóa không được đề cập bị trả về. Ví dụ: nếu chúng tôi có một tài liệu đăng blog trông như thế này

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
94

và chúng tôi đã thực hiện

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
001 để nhận được bình luận cuối cùng, chúng tôi sẽ nhận được điều này

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
95

Cả

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
005 và
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
006 vẫn được trả về, mặc dù chúng không được đưa vào bộ xác định khóa một cách rõ ràng

Trả về một phần tử mảng phù hợp

"

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
007" rất hữu ích khi bạn biết chỉ mục của phần tử, nhưng đôi khi bạn muốn bất kỳ phần tử mảng nào phù hợp với tiêu chí của bạn. Bạn có thể trả về phần tử khớp với toán tử
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
008. Với ví dụ về blog ở trên, bạn có thể lấy lại nhận xét của Bob bằng

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
96

Lưu ý rằng điều này chỉ trả về trận đấu đầu tiên cho mỗi tài liệu. nếu Bob đã để lại nhiều bình luận về bài đăng này, thì chỉ bình luận đầu tiên trong mảng "

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
009" sẽ được trả về

Tương tác truy vấn mảng và phạm vi

Số vô hướng (phần tử không phải mảng) trong tài liệu phải khớp với từng mệnh đề trong tiêu chí của truy vấn. Ví dụ: nếu bạn đã truy vấn cho

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
010, thì "
> db.users.find({"age" : 27})
63" phải vừa lớn hơn 10 vừa nhỏ hơn 20. Tuy nhiên, nếu trường "
> db.users.find({"age" : 27})
63" của tài liệu là một mảng, tài liệu sẽ khớp nếu có một phần tử của "
> db.users.find({"age" : 27})
63" khớp với từng phần của tiêu chí nhưng mỗi mệnh đề truy vấn có thể khớp với một phần tử mảng khác

Cách tốt nhất để hiểu hành vi này là xem một ví dụ. Giả sử chúng ta có các tài liệu sau

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
97

Nếu chúng tôi muốn tìm tất cả các tài liệu trong đó "

> db.users.find({"age" : 27})
63" nằm trong khoảng từ 10 đến 20, người ta có thể cấu trúc truy vấn một cách ngây thơ là
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
015 và mong muốn lấy lại một tài liệu.
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
016. Tuy nhiên, chạy này, chúng tôi nhận được hai

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
98

Cả 5 và 25 đều không nằm trong khoảng từ 10 đến 20, nhưng tài liệu được trả về vì 25 khớp với mệnh đề đầu tiên (nó lớn hơn 10) và 5 khớp với mệnh đề thứ hai (nó nhỏ hơn 20)

Điều này làm cho các truy vấn phạm vi đối với các mảng về cơ bản là vô dụng. một phạm vi sẽ khớp với bất kỳ mảng nhiều phần tử nào. Có một số cách để có được hành vi dự kiến

Đầu tiên, bạn có thể sử dụng "

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
017" để buộc MongoDB so sánh cả hai mệnh đề với một phần tử mảng. Tuy nhiên, điều đáng chú ý là "
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
017" sẽ không khớp với các phần tử không thuộc mảng

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
99

Tài liệu

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
016 không còn phù hợp với truy vấn, vì trường "
> db.users.find({"age" : 27})
63" không phải là một mảng

Nếu bạn có một chỉ mục trên trường mà bạn đang truy vấn (xem Chương 5), thì bạn có thể sử dụng

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
021 và
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
022 để giới hạn phạm vi chỉ mục mà truy vấn đi qua ở các giá trị "
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
023" và "
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
024" của bạn

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
20

Bây giờ điều này sẽ chỉ đi qua chỉ mục từ 10 đến 20, thiếu các mục 5 và 25. Tuy nhiên, bạn chỉ có thể sử dụng

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
021 và
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
022 khi bạn có chỉ mục trên trường mà bạn đang truy vấn và bạn phải chuyển tất cả các trường của chỉ mục tới
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
021 và
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
022

Sử dụng

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
021 và
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
022 khi truy vấn phạm vi trên tài liệu có thể bao gồm mảng nói chung là một ý kiến ​​hay. nếu bạn nhìn vào giới hạn chỉ mục cho truy vấn "
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
023“/”
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
024" trên một mảng, bạn có thể thấy rằng nó cực kỳ kém hiệu quả. Về cơ bản, nó chấp nhận bất kỳ giá trị nào, vì vậy nó sẽ tìm kiếm mọi mục nhập chỉ mục, không chỉ những mục trong phạm vi

Truy vấn trên các tài liệu nhúng

Có hai cách truy vấn cho một tài liệu được nhúng. truy vấn toàn bộ tài liệu hoặc truy vấn các cặp khóa/giá trị riêng lẻ của nó

Truy vấn cho toàn bộ tài liệu được nhúng hoạt động giống hệt với truy vấn thông thường. Ví dụ: nếu chúng ta có một tài liệu trông như thế này

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
21

chúng ta có thể truy vấn ai đó tên Joe Schmoe bằng cách sau

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
22

Tuy nhiên, truy vấn cho tài liệu phụ đầy đủ phải khớp chính xác với tài liệu phụ. Nếu Joe quyết định thêm trường tên đệm, đột nhiên truy vấn này sẽ không hoạt động nữa; . Loại truy vấn này cũng nhạy cảm với thứ tự.

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
033 sẽ không phù hợp

Nếu có thể, bạn nên truy vấn chỉ một hoặc nhiều khóa cụ thể của tài liệu được nhúng. Sau đó, nếu lược đồ của bạn thay đổi, tất cả các truy vấn của bạn sẽ không bị ngắt đột ngột vì chúng không còn khớp chính xác nữa. Bạn có thể truy vấn các khóa được nhúng bằng cách sử dụng ký hiệu dấu chấm

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
23

Bây giờ, nếu Joe thêm nhiều khóa hơn, truy vấn này sẽ vẫn khớp với họ và tên của anh ấy

Ký hiệu dấu chấm này là điểm khác biệt chính giữa tài liệu truy vấn và các loại tài liệu khác. Tài liệu truy vấn có thể chứa dấu chấm, có nghĩa là “tiếp cận tài liệu được nhúng. ” Dấu chấm cũng là lý do khiến tài liệu được chèn vào không thể chứa dấu chấm. nhân vật. Thông thường, mọi người gặp phải giới hạn này khi cố gắng lưu URL dưới dạng khóa. Một cách để giải quyết vấn đề này là luôn thực hiện thay thế toàn cầu trước khi chèn hoặc sau khi truy xuất, thay thế ký tự không hợp pháp trong URL bằng ký tự dấu chấm

Các kết quả khớp tài liệu được nhúng có thể hơi phức tạp vì cấu trúc tài liệu trở nên phức tạp hơn. Ví dụ: giả sử chúng tôi đang lưu trữ các bài đăng trên blog và chúng tôi muốn tìm các nhận xét của Joe đã được chấm điểm ít nhất là 5. Chúng ta có thể mô hình hóa bài đăng như sau

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
24

Bây giờ, chúng tôi không thể truy vấn bằng cách sử dụng

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
034. Các kết quả khớp tài liệu được nhúng phải khớp với toàn bộ tài liệu và điều này không khớp với khóa
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
035. Làm
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
036 cũng không hiệu quả, vì tiêu chí tác giả có thể khớp với một nhận xét khác với tiêu chí điểm số. Đó là, nó sẽ trả về tài liệu hiển thị ở trên. nó sẽ khớp với
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
037 trong bình luận đầu tiên và
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
038 trong bình luận thứ hai

Để nhóm chính xác các tiêu chí mà không cần chỉ định từng khóa, hãy sử dụng

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
039. Điều kiện có tên mơ hồ này cho phép bạn chỉ định một phần tiêu chí để khớp với một tài liệu được nhúng trong một mảng. Truy vấn chính xác trông như thế này

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
25

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
039 cho phép chúng tôi “nhóm” các tiêu chí của chúng tôi. Như vậy, nó chỉ cần thiết khi bạn có nhiều hơn một khóa mà bạn muốn khớp trong một tài liệu được nhúng

Các cặp khóa/giá trị là một cách khá biểu cảm để truy vấn, nhưng có một số truy vấn mà chúng không thể biểu diễn. Đối với các truy vấn không thể thực hiện theo bất kỳ cách nào khác, có các mệnh đề

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
041, cho phép bạn thực thi JavaScript tùy ý như một phần của truy vấn của mình. Điều này cho phép bạn làm (hầu hết) mọi thứ trong một truy vấn. Để bảo mật, việc sử dụng các mệnh đề "
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
042" nên được hạn chế hoặc loại bỏ. Người dùng cuối không bao giờ được phép thực thi mệnh đề "
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
042" tùy ý

Trường hợp phổ biến nhất khi sử dụng "

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
042" là so sánh giá trị của hai khóa trong tài liệu. Chẳng hạn, giả sử chúng ta có các tài liệu giống như thế này

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
26

Chúng tôi muốn trả về các tài liệu có hai trường bất kỳ bằng nhau. Ví dụ: trong tài liệu thứ hai,

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
045 và
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
046 có cùng giá trị, vì vậy chúng tôi muốn tài liệu đó được trả lại. MongoDB sẽ không bao giờ có điều kiện $ cho việc này, vì vậy chúng ta có thể sử dụng mệnh đề
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
041 để làm điều đó với JavaScript

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
27

Nếu hàm trả về

> db.users.find({"age" : 27})
37, tài liệu sẽ là một phần của tập kết quả;

Không nên sử dụng truy vấn

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
041 trừ khi thực sự cần thiết. chúng chậm hơn nhiều so với các truy vấn thông thường. Mỗi tài liệu phải được chuyển đổi từ BSON thành một đối tượng JavaScript và sau đó chạy qua biểu thức
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
041. Các chỉ mục không thể được sử dụng để đáp ứng một
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
041, hoặc. Do đó, bạn chỉ nên sử dụng
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
041 khi không còn cách nào khác để thực hiện truy vấn. Bạn có thể cắt giảm hình phạt bằng cách sử dụng các bộ lọc truy vấn khác kết hợp với
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
041. Nếu có thể, một chỉ mục sẽ được sử dụng để lọc dựa trên các mệnh đề không phải ___1042;

Một cách khác để thực hiện các truy vấn phức tạp là sử dụng một trong các công cụ tổng hợp có trong Chương 7

Bạn phải rất cẩn thận với bảo mật khi thực thi JavaScript trên máy chủ. Nếu được thực hiện không chính xác, JavaScript phía máy chủ dễ bị tấn công tiêm nhiễm tương tự như các cuộc tấn công xảy ra trong cơ sở dữ liệu quan hệ. Tuy nhiên, bằng cách tuân theo các quy tắc nhất định xung quanh việc chấp nhận đầu vào, bạn có thể sử dụng JavaScript một cách an toàn. Ngoài ra, bạn có thể tắt hoàn toàn việc thực thi JavaScript bằng cách chạy mongod với tùy chọn

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
057

Các vấn đề bảo mật với JavaScript đều liên quan đến việc thực thi các chương trình do người dùng cung cấp trên máy chủ. Bạn muốn tránh làm điều đó, vì vậy hãy đảm bảo rằng bạn không chấp nhận đầu vào của người dùng và chuyển trực tiếp thông tin đó đến mongod. Ví dụ: giả sử bạn muốn in “Xin chào,

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
058. ”, nơi mà người dùng cung cấp
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
058. Một cách tiếp cận ngây thơ có thể là viết một hàm JavaScript như sau

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
28

Nếu

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
058 là biến do người dùng định nghĩa, thì đó có thể là chuỗi
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
061, biến mã này thành

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
29

Bây giờ, nếu bạn chạy mã này, toàn bộ cơ sở dữ liệu của bạn sẽ bị hủy

Để ngăn chặn điều này, bạn nên sử dụng một phạm vi để chuyển tên. Ví dụ, trong Python, cái này trông như thế này

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
40

Bây giờ cơ sở dữ liệu sẽ in cái này một cách vô hại

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
41

Hầu hết các trình điều khiển đều có một loại đặc biệt để gửi mã đến cơ sở dữ liệu, vì mã thực sự có thể là sự kết hợp của một chuỗi và một phạm vi. Phạm vi là một tài liệu ánh xạ tên biến thành giá trị. Ánh xạ này trở thành phạm vi cục bộ cho chức năng JavaScript đang được thực thi. Do đó, trong ví dụ trên, hàm sẽ có quyền truy cập vào một biến có tên là

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
062, có giá trị là chuỗi mà người dùng đã cung cấp

Ghi chú

Shell không có loại mã bao gồm phạm vi;

Cơ sở dữ liệu trả về kết quả từ

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
2 bằng con trỏ. Việc triển khai con trỏ phía máy khách thường cho phép bạn kiểm soát rất nhiều về đầu ra cuối cùng của truy vấn. Bạn có thể giới hạn số lượng kết quả, bỏ qua một số kết quả, sắp xếp kết quả theo bất kỳ tổ hợp phím nào theo bất kỳ hướng nào và thực hiện một số thao tác mạnh mẽ khác

Để tạo con trỏ với trình bao, hãy đặt một số tài liệu vào bộ sưu tập, thực hiện truy vấn trên chúng và gán kết quả cho một biến cục bộ (các biến được xác định bằng

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
064 là cục bộ). Ở đây, chúng tôi tạo một bộ sưu tập rất đơn giản và truy vấn nó, lưu trữ kết quả trong biến
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
065

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
42

Ưu điểm của việc này là bạn có thể xem một kết quả tại một thời điểm. Nếu bạn lưu trữ kết quả trong một biến toàn cục hoặc không có biến nào cả, trình bao MongoDB sẽ tự động lặp lại và hiển thị một vài tài liệu đầu tiên. Đây là những gì chúng ta đã thấy cho đến thời điểm này và nó thường là hành vi bạn muốn để xem những gì trong một bộ sưu tập chứ không phải để thực hiện lập trình thực tế với trình bao

Để lặp qua các kết quả, bạn có thể sử dụng phương pháp

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
066 trên con trỏ. Bạn có thể sử dụng
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
067 để kiểm tra xem có kết quả nào khác không. Một vòng lặp điển hình thông qua các kết quả trông giống như sau

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
43

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
068 kiểm tra xem kết quả tiếp theo có tồn tại không và
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
069 tìm nạp nó

Lớp

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
065 cũng triển khai giao diện trình lặp của JavaScript, vì vậy bạn có thể sử dụng nó trong vòng lặp
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
071

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
44

Khi bạn gọi

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
2, trình bao không truy vấn cơ sở dữ liệu ngay lập tức. Nó đợi cho đến khi bạn bắt đầu yêu cầu kết quả để gửi truy vấn, điều này cho phép bạn xâu chuỗi các tùy chọn bổ sung vào một truy vấn trước khi nó được thực hiện. Hầu như mọi phương thức trên một đối tượng con trỏ đều trả về chính con trỏ để bạn có thể xâu chuỗi các tùy chọn theo bất kỳ thứ tự nào. Chẳng hạn, tất cả những điều sau đây là tương đương

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
45

Tại thời điểm này, truy vấn vẫn chưa được thực hiện. Tất cả các chức năng này chỉ đơn thuần là xây dựng truy vấn. Bây giờ, giả sử chúng ta gọi như sau

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
46

Tại thời điểm này, truy vấn sẽ được gửi đến máy chủ. Shell tìm nạp 100 kết quả đầu tiên hoặc 4 MB kết quả đầu tiên (tùy theo giá trị nào nhỏ hơn) cùng một lúc để các lệnh gọi tiếp theo tới

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
066 hoặc
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
067 sẽ không phải thực hiện các chuyến đi tới máy chủ. Sau khi máy khách chạy qua tập hợp kết quả đầu tiên, trình bao sẽ liên hệ lại với cơ sở dữ liệu và yêu cầu thêm kết quả với yêu cầu getMore. getMore về cơ bản chứa một mã định danh cho truy vấn và hỏi cơ sở dữ liệu xem có thêm kết quả nào không, trả về đợt tiếp theo nếu có. Quá trình này tiếp tục cho đến khi hết con trỏ và tất cả các kết quả đã được trả về

Các tùy chọn truy vấn phổ biến nhất là giới hạn số lượng kết quả trả về, bỏ qua một số kết quả và sắp xếp. Tất cả các tùy chọn này phải được thêm vào trước khi truy vấn được gửi đến cơ sở dữ liệu

Để đặt giới hạn, xâu chuỗi hàm

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
075 vào lệnh gọi của bạn tới
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
2. Ví dụ: để chỉ trả về ba kết quả, hãy sử dụng kết quả này

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
47

Nếu có ít hơn ba tài liệu phù hợp với truy vấn của bạn trong bộ sưu tập, thì chỉ số lượng tài liệu phù hợp sẽ được trả về;

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
078 hoạt động tương tự như
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
075

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
48

Thao tác này sẽ bỏ qua ba tài liệu khớp đầu tiên và trả về phần còn lại của các kết quả trùng khớp. Nếu có ít hơn ba tài liệu trong bộ sưu tập của bạn, nó sẽ không trả về bất kỳ tài liệu nào

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
080 lấy một đối tượng. một tập hợp các cặp khóa/giá trị trong đó khóa là tên khóa và giá trị là hướng sắp xếp. Hướng sắp xếp có thể là 1 (tăng dần) hoặc −1 (giảm dần). Nếu nhiều khóa được đưa ra, kết quả sẽ được sắp xếp theo thứ tự đó. Chẳng hạn, để sắp xếp kết quả theo
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
8 tăng dần và
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
7 giảm dần, chúng tôi thực hiện như sau

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
49

Ba phương pháp này có thể được kết hợp. Điều này thường thuận tiện cho việc phân trang. Ví dụ: giả sử bạn đang điều hành một cửa hàng trực tuyến và ai đó tìm kiếm mp3. Nếu bạn muốn 50 kết quả trên 1 trang sắp xếp theo giá từ cao xuống thấp thì có thể làm như sau

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
70

Nếu người đó nhấp vào Trang tiếp theo để xem thêm kết quả, bạn chỉ cần thêm một lượt bỏ qua vào truy vấn, lượt truy vấn này sẽ bỏ qua 50 kết quả khớp đầu tiên (mà người dùng đã xem trên trang 1)

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
71

Tuy nhiên, bỏ qua lớn không hiệu quả lắm;

MongoDB có một hệ thống phân cấp về cách so sánh các loại. Đôi khi bạn sẽ có một khóa duy nhất với nhiều loại. ví dụ: số nguyên và booleans hoặc chuỗi và null. Nếu bạn thực hiện sắp xếp trên một khóa có nhiều loại, thì sẽ có một thứ tự được xác định trước mà chúng sẽ được sắp xếp theo. Từ giá trị nhỏ nhất đến giá trị lớn nhất, thứ tự này như sau

  1. Giá trị tối thiểu

  2. > db.users.find({"age" : 27})
    67

  3. Số (số nguyên, số dài, gấp đôi)

  4. Dây

  5. Đối tượng/tài liệu

  6. Mảng

  7. Dữ liệu nhị phân

  8. ID đối tượng

  9. Boolean

  10. Ngày tháng

  11. Dấu thời gian

  12. Biểu hiện thông thường

  13. Gia trị lơn nhât

Sử dụng

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
078 cho một số ít tài liệu là tốt. Đối với một số lượng lớn kết quả,
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
078 có thể chậm, vì nó phải tìm và sau đó loại bỏ tất cả các kết quả bị bỏ qua. Hầu hết các cơ sở dữ liệu giữ nhiều siêu dữ liệu hơn trong chỉ mục để giúp bỏ qua, nhưng MongoDB chưa hỗ trợ điều này, vì vậy nên tránh các lần bỏ qua lớn. Thường thì bạn có thể tính truy vấn tiếp theo dựa trên kết quả từ truy vấn trước đó

Kết quả phân trang mà không bỏ qua

Cách dễ nhất để thực hiện phân trang là trả lại trang kết quả đầu tiên bằng cách sử dụng giới hạn và sau đó trả lại từng trang tiếp theo dưới dạng phần bù ngay từ đầu

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
72

Tuy nhiên, tùy thuộc vào truy vấn của bạn, thông thường bạn có thể tìm cách phân trang mà không cần

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
078s. Ví dụ: giả sử chúng tôi muốn hiển thị tài liệu theo thứ tự giảm dần dựa trên
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
087. Chúng tôi có thể nhận được trang kết quả đầu tiên với những điều sau đây

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
73

Sau đó, giả sử ngày là duy nhất, chúng ta có thể sử dụng giá trị

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
087 của tài liệu cuối cùng làm tiêu chí để tìm nạp trang tiếp theo

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
74

Bây giờ truy vấn không cần bao gồm

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
078

Tìm một tài liệu ngẫu nhiên

Một vấn đề khá phổ biến là làm thế nào để lấy một tài liệu ngẫu nhiên từ một bộ sưu tập. Giải pháp ngây thơ (và chậm chạp) là đếm số lượng tài liệu và sau đó thực hiện

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
2, bỏ qua một số lượng tài liệu ngẫu nhiên trong khoảng từ 0 đến kích thước của bộ sưu tập

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
75

Thực sự rất kém hiệu quả khi lấy một yếu tố ngẫu nhiên theo cách này. bạn phải đếm (có thể tốn kém nếu bạn đang sử dụng tiêu chí) và việc bỏ qua một số lượng lớn các phần tử có thể tốn thời gian

Cần phải suy nghĩ trước một chút, nhưng nếu bạn biết mình sẽ tìm kiếm một phần tử ngẫu nhiên trên một bộ sưu tập, thì có một cách hiệu quả hơn nhiều để làm điều đó. Mẹo nhỏ là thêm một khóa ngẫu nhiên vào mỗi tài liệu khi nó được chèn vào. Chẳng hạn, nếu đang sử dụng trình bao, chúng ta có thể sử dụng hàm

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
091 (tạo một số ngẫu nhiên trong khoảng từ 0 đến 1)

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
76

Bây giờ, khi chúng tôi muốn tìm một tài liệu ngẫu nhiên từ bộ sưu tập, chúng tôi có thể tính toán một số ngẫu nhiên và sử dụng số đó làm tiêu chí truy vấn, thay vì thực hiện

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
078

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
77

Có một khả năng nhỏ là

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
093 sẽ lớn hơn bất kỳ giá trị nào của
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
094 trong bộ sưu tập và sẽ không có kết quả nào được trả về. Chúng tôi có thể bảo vệ chống lại điều này bằng cách chỉ cần trả lại một tài liệu theo hướng khác

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
78

Nếu không có bất kỳ tài liệu nào trong bộ sưu tập, kỹ thuật này sẽ kết thúc trả về

> db.users.find({"age" : 27})
67, điều này hợp lý

Kỹ thuật này có thể được sử dụng với các truy vấn phức tạp tùy ý; . Ví dụ: nếu chúng tôi muốn tìm một thợ sửa ống nước ngẫu nhiên ở California, chúng tôi có thể tạo một chỉ mục trên

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
096,
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
097 và
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
094

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
79

Điều này cho phép chúng tôi nhanh chóng tìm thấy một kết quả ngẫu nhiên (xem Chương 5 để biết thêm thông tin về lập chỉ mục)

Có hai loại truy vấn. bọc và đồng bằng. Một truy vấn đơn giản là một cái gì đó như thế này

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
10

Có một số tùy chọn “bao bọc” truy vấn. Ví dụ: giả sử chúng ta thực hiện sắp xếp

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
11

Thay vì gửi

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
099 tới cơ sở dữ liệu dưới dạng truy vấn, truy vấn sẽ được bao bọc trong một tài liệu lớn hơn. Shell chuyển đổi truy vấn từ
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
099 thành
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
401

Hầu hết các trình điều khiển cung cấp trình trợ giúp để thêm tùy chọn tùy ý vào truy vấn. Các tùy chọn hữu ích khác bao gồm những điều sau đây

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
402

Chỉ định số lượng tài liệu tối đa sẽ được quét cho truy vấn

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
12

Điều này có thể hữu ích nếu bạn muốn một truy vấn không mất quá nhiều thời gian nhưng không chắc sẽ cần quét bao nhiêu bộ sưu tập. Điều này sẽ giới hạn kết quả của bạn ở bất kỳ thứ gì được tìm thấy trong phần của bộ sưu tập đã được quét (tôi. e. , bạn có thể bỏ lỡ các tài liệu khác phù hợp)

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
403

Tiêu chí bắt đầu truy vấn.

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
404 phải khớp chính xác với các khóa của chỉ mục được sử dụng cho truy vấn. Điều này buộc chỉ mục đã cho được sử dụng cho truy vấn

Điều này được sử dụng nội bộ và bạn thường nên sử dụng

> db.users.find({"age" : 27})
17 thay vì
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
406. Bạn có thể sử dụng
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
406 để buộc giới hạn dưới khi quét chỉ mục, điều này có thể hữu ích cho các truy vấn phức tạp

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
408

Tiêu chí kết thúc truy vấn.

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
404 phải khớp chính xác với các khóa của chỉ mục được sử dụng cho truy vấn. Điều này buộc chỉ mục đã cho được sử dụng cho truy vấn

Nếu điều này được sử dụng nội bộ, bạn thường nên sử dụng

> db.users.find({"age" : 27})
15 thay vì
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
411. Bạn có thể sử dụng
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
411 để buộc giới hạn khi quét chỉ mục, điều này có thể hữu ích cho các truy vấn phức tạp

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
413

Thêm trường "

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
414" vào kết quả cho biết vị trí của kết quả cụ thể đó trên đĩa. Ví dụ

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
13

Số tệp cho biết tài liệu nằm trong tệp nào. Trong trường hợp này, nếu chúng tôi đang sử dụng cơ sở dữ liệu thử nghiệm, thì tài liệu đang trong quá trình thử nghiệm. 2. Trường thứ hai cung cấp độ lệch byte của từng tài liệu trong tệp

Nhận kết quả nhất quán

Một cách khá phổ biến để xử lý dữ liệu là kéo nó ra khỏi MongoDB, thay đổi nó theo một cách nào đó rồi lưu lại

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
14

Điều này tốt cho một số ít kết quả, nhưng MongoDB có thể trả về cùng một kết quả nhiều lần cho một tập kết quả lớn. Để biết lý do tại sao, hãy tưởng tượng các tài liệu đang được lưu trữ như thế nào. Bạn có thể hình dung một bộ sưu tập dưới dạng một danh sách các tài liệu trông giống như Hình 4-1. Bông tuyết đại diện cho các tài liệu, vì mọi tài liệu đều đẹp và độc đáo

Tìm kiếm mongodb hoạt động như thế nào?

Hình 4-1. Một bộ sưu tập đang được truy vấn

Bây giờ, khi chúng ta thực hiện một

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
2, con trỏ bắt đầu trả về kết quả từ đầu tập hợp và di chuyển sang phải. Chương trình của bạn lấy 100 tài liệu đầu tiên và xử lý chúng. Khi bạn lưu chúng trở lại cơ sở dữ liệu, nếu tài liệu không có sẵn phần đệm để tăng kích thước mới, như trong Hình 4-2, thì tài liệu đó cần được di chuyển. Thông thường, một tài liệu sẽ được chuyển đến cuối bộ sưu tập (Hình 4-3)

Tìm kiếm mongodb hoạt động như thế nào?

Hình 4-2. Một tài liệu được phóng to có thể không vừa với vị trí trước đó

Tìm kiếm mongodb hoạt động như thế nào?

Hình 4-3. MongoDB di chuyển các tài liệu đã cập nhật không vừa với vị trí ban đầu của chúng

Bây giờ chương trình của chúng tôi tiếp tục tìm nạp các lô tài liệu. Khi gần hết, nó sẽ trả lại các tài liệu đã di chuyển (Hình 4-4)

Tìm kiếm mongodb hoạt động như thế nào?

Hình 4-4. Một con trỏ có thể trả lại các tài liệu đã di chuyển này một lần nữa trong đợt sau

Giải pháp cho vấn đề này là chụp nhanh truy vấn của bạn. Nếu bạn thêm tùy chọn này, truy vấn sẽ được chạy bằng cách duyệt qua chỉ mục "

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
416", điều này đảm bảo rằng bạn sẽ chỉ trả về mỗi tài liệu một lần. Ví dụ: thay vì
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
417, bạn sẽ chạy

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
15

Chụp nhanh làm cho truy vấn chậm hơn, vì vậy chỉ sử dụng truy vấn được chụp nhanh khi cần thiết. Ví dụ: mongodump (một tiện ích sao lưu có trong Chương 22) sử dụng các truy vấn được chụp nhanh theo mặc định

Tất cả các truy vấn trả về một lô kết quả đều được chụp nhanh một cách hiệu quả. Sự không nhất quán chỉ phát sinh khi bộ sưu tập thay đổi dưới con trỏ trong khi nó đang chờ nhận một loạt kết quả khác

Có hai mặt của một con trỏ. con trỏ phía máy khách và con trỏ cơ sở dữ liệu mà con trỏ phía máy khách đại diện. Chúng tôi đã nói về phía máy khách cho đến bây giờ, nhưng chúng tôi sẽ xem xét sơ qua những gì đang xảy ra trên máy chủ

Về phía máy chủ, một con trỏ chiếm bộ nhớ và tài nguyên. Khi một con trỏ hết kết quả hoặc máy khách gửi thông báo báo nó chết, cơ sở dữ liệu có thể giải phóng các tài nguyên mà nó đang sử dụng. Giải phóng các tài nguyên này cho phép cơ sở dữ liệu sử dụng chúng cho những thứ khác, điều này tốt, vì vậy chúng tôi muốn đảm bảo rằng các con trỏ có thể được giải phóng nhanh chóng (trong lý do)

Có một số điều kiện có thể gây ra cái chết (và việc dọn dẹp sau đó) của con trỏ. Đầu tiên, khi một con trỏ hoàn thành việc lặp qua các kết quả phù hợp, nó sẽ tự dọn sạch. Một cách khác là, khi một con trỏ nằm ngoài phạm vi ở phía máy khách, các trình điều khiển sẽ gửi cho cơ sở dữ liệu một thông báo đặc biệt để cho nó biết rằng nó có thể giết con trỏ đó. Cuối cùng, ngay cả khi người dùng chưa duyệt qua tất cả các kết quả và con trỏ vẫn nằm trong phạm vi, sau 10 phút không hoạt động, con trỏ cơ sở dữ liệu sẽ tự động “chết”. ” Bằng cách này, nếu máy khách gặp sự cố hoặc có lỗi, MongoDB sẽ không bị bỏ lại với hàng nghìn con trỏ đang mở

"Chết do hết thời gian chờ" này thường là hành vi mong muốn. rất ít ứng dụng mong muốn người dùng của họ ngồi hàng phút chờ đợi kết quả. Tuy nhiên, đôi khi bạn có thể biết rằng bạn cần một con trỏ để tồn tại trong một thời gian dài. Trong trường hợp đó, nhiều trình điều khiển đã triển khai một chức năng có tên là

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
418 hoặc một cơ chế tương tự, cho biết cơ sở dữ liệu không hết thời gian chờ con trỏ. Nếu bạn tắt thời gian chờ của con trỏ, bạn phải lặp lại tất cả các kết quả của nó hoặc tắt nó để đảm bảo nó được đóng lại. Nếu không, nó sẽ nằm loanh quanh trong cơ sở dữ liệu ngốn tài nguyên cho đến khi máy chủ được khởi động lại

Có một loại truy vấn rất đặc biệt được gọi là lệnh cơ sở dữ liệu. Chúng tôi đã đề cập đến việc tạo, cập nhật, xóa và tìm tài liệu. Các lệnh cơ sở dữ liệu thực hiện “mọi thứ khác”, từ các tác vụ quản trị như tắt máy chủ và sao chép cơ sở dữ liệu đến đếm tài liệu trong bộ sưu tập và thực hiện tổng hợp

Các lệnh được đề cập xuyên suốt văn bản này, vì chúng rất hữu ích cho việc thao tác, quản trị và giám sát dữ liệu. Ví dụ: xóa một bộ sưu tập được thực hiện thông qua lệnh cơ sở dữ liệu "______1419"

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
16

Bạn có thể quen thuộc hơn với trình trợ giúp shell, trình bao bọc lệnh và cung cấp giao diện đơn giản hơn

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
17

Thường thì bạn chỉ có thể sử dụng trình trợ giúp trình bao, nhưng biết các lệnh cơ bản có thể hữu ích nếu bạn bị mắc kẹt trong một hộp có phiên bản trình bao cũ và được kết nối với phiên bản cơ sở dữ liệu mới. trình bao có thể không có trình bao bọc cho các lệnh cơ sở dữ liệu mới, nhưng bạn vẫn có thể chạy chúng với

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
420

Chúng ta đã thấy một vài lệnh trong các chương trước;

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
18

Trong phần này, chúng ta sẽ xem xét kỹ hơn các lệnh để biết chính xác chúng là gì và chúng được triển khai như thế nào. Chúng tôi cũng sẽ mô tả một số lệnh hữu ích nhất được MongoDB hỗ trợ. Bạn có thể xem tất cả các lệnh bằng cách chạy lệnh

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
422

Một lệnh cơ sở dữ liệu luôn trả về một tài liệu chứa khóa

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
423. Nếu
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
423 là giá trị thực (
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
425,
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
426 hoặc
> db.users.find({"age" : 27})
37), lệnh đã thành công;

Nếu

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
423 là
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
430 thì sẽ có một khóa bổ sung,
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
431. Giá trị của
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
431 là một chuỗi giải thích tại sao lệnh không thành công. Ví dụ: hãy thử chạy lại lệnh
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
419, trên bộ sưu tập đã bị loại bỏ trong phần trước

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
19

Các lệnh trong MongoDB được triển khai dưới dạng một loại truy vấn đặc biệt được thực hiện trên bộ sưu tập $cmd.

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
434 chỉ lấy một tài liệu lệnh và thực hiện truy vấn tương đương, vì vậy cuộc gọi thả của chúng tôi trở thành như sau

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
0

Khi máy chủ MongoDB nhận được một truy vấn trên bộ sưu tập $cmd, nó sẽ xử lý truy vấn đó bằng cách sử dụng logic đặc biệt, thay vì mã thông thường để xử lý các truy vấn. Hầu như tất cả các trình điều khiển MongoDB đều cung cấp một phương thức trợ giúp như

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
434 để chạy các lệnh, nhưng các lệnh luôn có thể được chạy bằng một truy vấn đơn giản

Một số lệnh yêu cầu quyền truy cập của quản trị viên và phải được chạy trên cơ sở dữ liệu quản trị viên. Nếu một lệnh như vậy được chạy trên bất kỳ cơ sở dữ liệu nào khác, nó sẽ trả về lỗi

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
436. Nếu bạn đang làm việc trên cơ sở dữ liệu khác và cần chạy lệnh quản trị viên, bạn có thể sử dụng hàm
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
437, thay vì hàm
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
434

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
1

Các lệnh là một trong số ít nơi nhạy cảm với thứ tự trường. tên lệnh phải luôn là trường đầu tiên trong lệnh. Do đó,

> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
439 sẽ hoạt động, nhưng
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
440 sẽ không

MongoDB có tốt cho việc tìm kiếm không?

MongoDB đã tạo định dạng JSON nhị phân (BSON) để hỗ trợ nhiều loại dữ liệu hơn JSON. Định dạng mới này cho phép phân tích dữ liệu nhanh hơn. Dữ liệu được lưu trữ trong BSON có thể được tìm kiếm và lập chỉ mục, giúp tăng đáng kể hiệu suất .

Làm cách nào để triển khai tìm kiếm trong MongoDB?

Triển khai tìm kiếm toàn văn bản trong MongoDB Atlas . Go to any cluster and select the “Search” tab to do so. Từ đó, bạn có thể nhấp vào “Tạo chỉ mục tìm kiếm” để khởi chạy quy trình. Khi chỉ mục được tạo, bạn có thể sử dụng toán tử $search để thực hiện tìm kiếm toàn văn. db.

Tìm kiếm hoạt động như thế nào trong NoSQL?

Có hai cách khác nhau mà hệ thống NoSQL lưu trữ các chỉ mục tìm kiếm. chỉ mục trong nút và sử dụng dịch vụ tìm kiếm từ xa . Hầu hết các hệ thống NoSQL giữ dữ liệu và chỉ mục của chúng trên cùng một nút. Nhưng một số hệ thống NoSQL sử dụng các dịch vụ tìm kiếm bên ngoài để tìm kiếm toàn văn.

Tìm kiếm MongoDB Atlas hoạt động như thế nào?

Atlas Search là tìm kiếm toàn văn được nhúng trong MongoDB Atlas mang đến cho bạn trải nghiệm liền mạch, có thể mở rộng để xây dựng các tính năng ứng dụng dựa trên mức độ liên quan . Được xây dựng trên Apache Lucene, Atlas Search loại bỏ nhu cầu chạy một hệ thống tìm kiếm riêng biệt cùng với cơ sở dữ liệu của bạn.