2015-04-11 34 views
31

Kiểu dữ liệu của trường là Chuỗi. Tôi muốn tìm nạp dữ liệu mà độ dài ký tự của tên trường lớn hơn 40.Độ dài giá trị trường chuỗi trong mongoDB

Tôi đã thử các truy vấn này nhưng trả lại lỗi. 1.

db.usercollection.find(
{$where: "(this.name.length > 40)"} 
).limit(2); 

output :error: { 
    "$err" : "TypeError: Cannot read property 'length' of undefined near '40)' ", 
    "code" : 16722 
} 

này đang làm việc tại 2.4.9 Nhưng phiên bản của tôi là 2.6.5

+1

Bạn đã thử gt thay vì> – gpullen

Trả lời

75

Đối với MongoDB 3.6 và mới hơn:

Nhà điều hành $expr cho phép việc sử dụng các tập hợp biểu thức trong ngôn ngữ truy vấn, do đó bạn có thể tận dụng việc sử dụng toán tử $strLenCP để kiểm tra độ dài của chuỗi như sau:

db.usercollection.find({ 
    "name": { "$exists": true } }, 
    "$expr": { "$gt": [ { "$strLenCP": "$name" }, 40 ] } 
}) 

Đối với MongoDB 3.4 và mới hơn:

Bạn cũng có thể sử dụng khuôn khổ hợp với các nhà điều hành $redact đường ống cho phép bạn proccess điều kiện hợp lý với các nhà điều hành $cond và sử dụng các hoạt động đặc biệt $$KEEP để "giữ" tài liệu ở nơi điều kiện logic là đúng hoặc $$PRUNE để "xóa" tài liệu trong đó điều kiện sai.

Thao tác này cũng tương tự như việc có một đường ống $project mà lựa chọn các trường trong việc thu thập và tạo ra một lĩnh vực mới chứa kết quả từ truy vấn tình trạng hợp lý và sau đó một tiếp theo $match, ngoại trừ việc $redact sử dụng một giai đoạn đường ống duy nhất hiệu quả hơn.

Đối với điều kiện logic, có String Aggregation Operators bạn có thể sử dụng toán tử $strLenCP để kiểm tra độ dài của chuỗi. Nếu độ dài là $gt giá trị được chỉ định, thì đây là giá trị phù hợp và tài liệu được "lưu giữ". Nếu không, nó được "cắt xén" và bị loại bỏ.


xem xét việc chạy các hoạt động tổng hợp sau đó chứng minh khái niệm trên:

db.usercollection.aggregate([ 
    { "$match": { "name": { "$exists": true } } }, 
    { 
     "$redact": { 
      "$cond": [ 
       { "$gt": [ { "$strLenCP": "$name" }, 40] }, 
       "$$KEEP", 
       "$$PRUNE" 
      ] 
     } 
    }, 
    { "$limit": 2 } 
]) 

Nếu sử dụng $where, hãy thử truy vấn của bạn không có dấu ngoặc kèm theo:

db.usercollection.find({$where: "this.name.length > 40"}).limit(2); 

Một tốt hơn truy vấn sẽ là để kiểm tra sự tồn tại của trường và sau đó kiểm tra lengt h:

db.usercollection.find({name: {$type: 2}, $where: "this.name.length > 40"}).limit(2); 

hay:

db.usercollection.find({name: {$exists: true}, $where: "this.name.length > 
40"}).limit(2); 

MongoDB đánh giá các hoạt động phi $where truy vấn trước khi $where biểu thức và phi $where câu lệnh truy vấn có thể sử dụng một chỉ mục. Một hiệu suất tốt hơn nhiều là lưu trữ độ dài của chuỗi như một trường khác và sau đó bạn có thể lập chỉ mục hoặc tìm kiếm trên đó; áp dụng $where sẽ chậm hơn nhiều so với điều đó. Bạn nên sử dụng biểu thức JavaScript và toán tử $where làm phương sách cuối cùng khi bạn không thể cấu trúc dữ liệu theo bất kỳ cách nào khác hoặc khi bạn đang xử lý một tập hợp con dữ liệu nhỏ .


Một cách tiếp cận khác nhau và nhanh hơn mà tránh được việc sử dụng các nhà điều hành $where là các nhà điều hành $regex. Hãy xem xét các mô hình sau đó tìm kiếm

db.usercollection.find({"name": {"$type": 2, "$regex": /^.{41,}$/}}).limit(2); 

Note - Từ docs:

Nếu một chỉ số tồn tại cho lĩnh vực này, sau đó MongoDB phù hợp với biểu thức chính quy đối với các giá trị trong chỉ mục, có thể nhanh hơn so với quét bộ sưu tập . Tối ưu hóa thêm có thể xảy ra nếu biểu thức thông thường là "biểu thức tiền tố", có nghĩa là tất cả các đối sánh có thể là bắt đầu bằng cùng một chuỗi. Điều này cho phép MongoDB xây dựng một “phạm vi” từ tiền tố đó và chỉ khớp với các giá trị đó từ chỉ mục nằm trong phạm vi đó.

Một biểu thức chính quy là một “biểu hiện tiền tố” nếu nó bắt đầu với một caret (^) hoặc neo trái (\A), tiếp theo là một chuỗi các ký tự đơn giản. Ví dụ: regex /^abc.*/ sẽ được tối ưu hóa bởi chỉ khớp với các giá trị từ chỉ mục bắt đầu bằng abc.

Ngoài ra, trong khi /^a/, /^a.*/,/^a.*$/ khớp tương đương với chuỗi, chúng có đặc điểm hiệu suất khác nhau. Tất cả các biểu thức này sử dụng chỉ mục nếu chỉ mục thích hợp tồn tại; tuy nhiên, /^a.*//^a.*$/ chậm hơn. /^a/ có thể ngừng quét sau khi khớp với tiền tố.

+0

Tất cả 3 truy vấn đều hoạt động tốt. Nhưng cái đầu tiên là chấp nhận tối đa 15. nghĩa là "this.name.length> 15". Nếu chúng ta đưa ra 16 hoặc cao hơn thì nó sẽ đưa ra cùng một lỗi. –

+0

Nếu chúng ta muốn thực hiện tương tự cho tài liệu bên trong như profile.name thì bạn có thể gợi ý cú pháp cho nó không. –

+1

Đối với trường tài liệu được nhúng, hãy thử 'db.usercollection.find ({" profile.name ": {$ type: 2}, $ where:" this.profile.name.length> 40 "}) .giới hạn (2); ' – chridam

1

Tôi đã có một loại tương tự của kịch bản, nhưng trong trường hợp của tôi chuỗi không phải là một thuộc tính cấp 1. Nó ở trong một vật thể. Ở đây tôi không thể tìm ra câu trả lời phù hợp cho nó. Vì vậy, tôi nghĩ rằng để chia sẻ giải pháp của tôi với tất cả các bạn (Hy vọng điều này sẽ giúp bất cứ ai với một loại tương tự của vấn đề).

Parent Collection 

{ 
"Child": 
{ 
"name":"Random Name", 
"Age:"09" 
} 
} 

Ví dụ: Nếu chúng tôi chỉ nhận được các bộ sưu tập có độ dài tên của trẻ cao hơn 10 ký tự.

db.getCollection('Parent').find({$where: function() { 
for (var field in this.Child.name) { 
    if (this.Child.name.length > 10) 
     return true; 

} 
}}) 
Các vấn đề liên quan