Given a mongoose object. How can I do a full text search in document object
{
"product" :[
{
"_id": "633d32c4ea9b06177e183388",
"document": {
"_id": "633d32c4ea9b06177e183388",
"category": [
"62bacb137e6e0b6ac850b9ce",
"633d19260b72ba127d928e74"
],
"name": "Iphone 13",
"slug": "iphone-13",
"__v": 0,
"price": 2000.5,
"images": [
{
"_id": "63cca1a271c3635246eee937",
"url": "https://res.cloudinary.com/..."
}
],
"sold": 15,
"ratings": []
},
"avgRating": null
},
...
]
}
This is what I have tried but it doesn’t work
const product = await Product.aggregate([
{
$project: {
document: "$$ROOT",
avgRating: {
$floor: { $avg: "$ratings.star" },
},
},
},
{
$match: {
document: { $text: { $search: `"${searchText}"` } },
},
},
]);
This is my product Model
const product = {
name: {
type: String,
required: true,
trim: true,
minlength: [2, "Too short"],
maxlength: [32, "Too long"],
unique: true,
},
slug: {
type: String,
unique: true,
lowercase: true,
index: true,
},
category: [
{
type: ObjectId,
ref: "Category",
},
],
description: {
type: String,
maxlength: 200,
},
price: {
type: Number,
required: true,
trim: true,
maxlength: 32,
},
shipping: {
type: String,
enum: ["Yes", "No"],
},
color: [
{
type: String,
enum: ["Black", "Brown", "Silver", "White", "Blue"],
},
],
sold: {
type: Number,
default: 0,
},
quantity: {
type: Number,
},
images: [
{
public_id: String,
url: String,
},
],
ratings: [
{
star: Number,
postedBy: {
type: ObjectId,
ref: "User",
},
},
],
};
The goal is to aggregate product ratings by getting the average of product ratings star then chain multiple where clauses , one of the where clause is to perform a full text search in the document object.
Kindly advise.
Thank you.
2
Answers
From the docs:
So it should work if you flip your pipeline order:
This would be faster as you are running your project stage only on documents which match the search, rather than the entire collection.
$text
requires atext index
on the field, whose contents are to be searched. In your case, you are using$text
on a document, rather than a text field, so most likely it will give unexpected results. One way to solve this is to add a field in your schema let’s saytextContent
, which is a stringified version of your document, and then create atext index
on this field. So your pipeline would become something like this:Note: I have moved $match above because it’s expected to be the first stage of the pipeline. Refer to
$text
documentation here.