Sửa lỗi MongoDB: 'text index required for $text query'

intermediate🍃 MongoDB2026-07-15| MongoDB (Tất cả phiên bản), Node.js (Mongoose/MongoDB Driver), Python (PyMongo), MongoDB Shell

Error Message

MongoServerError: text index required for $text query
#mongodb#mongoose#database-indexing#full-text-search

Vấn đềBạn đang cố gắng thực hiện tìm kiếm toàn văn (full-text search) trong MongoDB bằng toán tử $text, nhưng thay vì kết quả, bạn lại nhận được một thông báo lỗi. Nó thường trông như thế này:

MongoServerError: text index required for $text query

Tôi đã gặp lỗi này gần đây khi xây dựng thanh tìm kiếm cho một trang tài liệu. Tôi muốn tìm các từ khóa trong tiêu đề và nội dung bài viết bằng một truy vấn như sau:

db.articles.find({ $text: { $search: "performance optimization" } })

Có vẻ như nó sẽ hoạt động. Tuy nhiên, MongoDB xử lý tìm kiếm toàn văn khác với việc tra cứu trường thông thường. Trong khi một truy vấn như { status: "active" } có thể chạy (mặc dù chậm) mà không cần index, thì truy vấn $text về mặt kỹ thuật không thể thực thi cho đến khi bạn xác định một text index.

Tại sao điều này xảy raBên dưới hệ thống, toán tử $text thực hiện rất nhiều công việc nặng nhọc. Nó thực hiện stemming (biến đổi các từ về gốc, ví dụ "running" thành "run"), loại bỏ các từ dừng (stop words) như "the" hoặc "and," và tách từ (tokenize) chuỗi. Để thực hiện việc này hiệu quả, MongoDB yêu cầu một cấu trúc dữ liệu chuyên biệt. Nếu bạn chưa khai báo cho cơ sở dữ liệu biết trường nào cần đưa vào cấu trúc này, nó sẽ không có bản đồ để tuân theo. Kết quả là nó sẽ dừng lại và báo lỗi.

Cách khắc phục từng bước### 1. Kiểm tra các index hiện cóBắt đầu bằng cách xem những index nào đã tồn tại. Chạy lệnh này trong MongoDB Shell (mongosh):

db.articles.getIndexes()

Nhìn vào kết quả. Nếu bạn không thấy một khóa (key) nào có giá trị là "text", đó chính là phần còn thiếu. Bạn có thể thấy _id_ hoặc một index trên trường category, nhưng chúng sẽ không giúp ích cho việc tìm kiếm văn bản.

2. Tạo Text IndexBạn cần chỉ định rõ ràng cho MongoDB những trường nào cần lập chỉ mục để tìm kiếm. Nếu bạn muốn tìm kiếm trên cả hai trường titlecontent, hãy chạy lệnh này:

db.articles.createIndex({ 
  title: "text", 
  content: "text" 
})

Trong MongoDB 4.2 và mới hơn, quá trình này diễn ra ở chế độ nền (background) theo mặc định. Nó sẽ không khóa cơ sở dữ liệu của bạn, nhưng sẽ tiêu tốn tài nguyên I/O. Đối với một collection có 1 triệu tài liệu nhỏ, việc này có thể mất từ 30 đến 60 giây tùy thuộc vào phần cứng của bạn.

3. Sử dụng Wildcard để "Tìm kiếm mọi thứ"Nếu bạn đang thử nghiệm và muốn tìm kiếm trên mọi trường văn bản mà không cần liệt kê tất cả, hãy sử dụng ký tự đại diện (wildcard):

db.collection.createIndex({ "$**": "text" })

Hãy thận trọng khi sử dụng lệnh này. Một wildcard text index có thể dễ dàng làm tăng dung lượng lưu trữ thêm 30% hoặc hơn vì nó lập chỉ mục cho mọi chuỗi văn bản trong tài liệu.

Khắc phục trong Mongoose (Node.js)Nếu bạn sử dụng Mongoose, đừng chỉ sửa lỗi trong shell. Bạn cần cập nhật Schema của mình để index được duy trì khi bạn triển khai lên môi trường production. Dưới đây là cách thiết lập sạch sẽ:

const articleSchema = new mongoose.Schema({
  title: String,
  content: String,
  author: String
});

// Định nghĩa text index ở cấp độ schema
articleSchema.index({ title: 'text', content: 'text' });

const Article = mongoose.model('Article', articleSchema);

Một cảnh báo nhỏ: Mongoose tạo index khi ứng dụng khởi động. Nếu bạn đã có một index khác trên collection đó, Mongoose có thể thất bại trong việc tạo index mới một cách âm thầm. Nếu lỗi vẫn còn, hãy xóa các index hiện có trong shell bằng db.articles.dropIndexes() và khởi động lại server Node của bạn.

Quy tắc "Một Index"Một sai lầm phổ biến là cố gắng tạo nhiều text index. MongoDB chỉ cho phép duy nhất một text index cho mỗi collection. Nếu bạn cố gắng chạy chúng dưới dạng hai lệnh riêng biệt, lệnh thứ hai sẽ thất bại:

db.posts.createIndex({ title: "text" })
db.posts.createIndex({ description: "text" }) // Lỗi!

Để tìm kiếm trên cả hai trường, bạn phải kết hợp chúng thành một index hỗn hợp (compound index) duy nhất như đã trình bày ở Bước 2.

Cách xác minh việc khắc phụcSau khi tạo index, hãy kiểm tra xem truy vấn của bạn có thực sự sử dụng nó hay không. Thêm .explain("executionStats") vào truy vấn của bạn:

db.articles.find({ $text: { $search: "database" } }).explain("executionStats")

Trong kết quả đầu ra, hãy tìm winningPlan. Nếu bạn thấy một giai đoạn (stage) có tên là TEXT_MATCH, nghĩa là bạn đã thành công. Lỗi sẽ biến mất và kết quả tìm kiếm của bạn sẽ xuất hiện ngay lập tức.

Những lưu ý quan trọng- Chi phí lưu trữ: Text index lớn hơn nhiều so với các index B-tree tiêu chuẩn. Hãy chuẩn bị cho việc tăng đáng kể mức sử dụng RAM và đĩa cứng.- Trọng số (Weights): Bạn có thể làm cho trường title quan trọng hơn trường body bằng cách gán trọng số (ví dụ: { title: "text", content: "text" }, { weights: { title: 10, content: 2 } }).- Ngôn ngữ: MongoDB mặc định là tiếng Anh. Nếu nội dung của bạn bằng tiếng Pháp hoặc tiếng Tây Ban Nha, hãy chỉ định default_language trong các tùy chọn index để đảm bảo quá trình stemming hoạt động chính xác.

Related Error Notes