'Full text Search returns empty array using mongoose and Node.js

None of the other SO articles got me a solution.

Schema Definition:

const jobSchema = new (require("mongoose").Schema)(
  {
    userID: { type: require("mongoose").Schema.Types.ObjectId, ref: "User" },
    emailID: { type: String, trim: true, required: false },
    jobTitle: { type: String, trim: true, required: false },
    jobDescription: { type: String, trim: true, required: false },
    company: { type: String, required: false },
    position: { type: String, required: false },
    noOfYearsExperience: { type: String, required: false },
    domain: { type: String, required: false },
    link: { type: String, required: false },
    location: { type: String, required: false },
    jobCreationStatus: { type: String, required: false },
    isActive: { type: Boolean, default: true, required: false },
    isFeatured: { type: Boolean, default: false, required: false },
    ttl: { type: String, required: false },
    expiryDate: { type: Date, required: false },
    expired: { type: Boolean, default: false, required: false },
    applicants: [{ userId: { type: require("mongoose").Schema.Types.ObjectId, ref: "User" } }],
  },
  {
    timestamps: true,
  }
);

jobSchema.index({ jobTitle: "text", domain: "text", location: "text" }, { weights: { jobTitle: 3, domain: 2, location: 1 } });

Query Function:

module.exports.getJobs = async (filters, searchText, pageNo, isAuth) => {
  try {
    if (!filters["expired"]) filters["expired"] = false;
    if (!searchText) searchText = null;
    return await Job.aggregate([
      // { $match: { $or: [filters, { $text: { $search: "Kolkata" } }] } },
      { $match: { $text: { $search: "Kolkata" } } },
      {
        $facet: {
          metadata: [{ $count: "total" }, { $addFields: { page: pageNo } }],
          data: [{ $skip: pageNo * 30 }, { $limit: 30 }],
        },
      },
    ]);
  } catch (err) {
    console.log(err);
  }
};

The exact behavior I want: If searchText is null, match the filters. Else, just return the documents that match the searchText on the indexed fields. "Kolkata" is to be replaced by searchText.

The problem: If the given $match are removed from the aggregate above, the query works fine. Response in Postman:

{
    "status": "success",
    "message": [
        {
            "metadata": [
                {
                    "total": 1,
                    "page": 0
                }
            ],
            "data": [
                {
                    "_id": "620aa56f5966e4052229232c",
                    "emailID": "[email protected]",
                    "company": "SpaceShift",
                    "noOfYearsExperience": "4",
                    "domain": "Angulaar, React",
                    "location": "Kolkata",
                    "jobCreationStatus": "job",
                    "isActive": true,
                    "ttl": "2 week",
                    "expired": false,
                    "createdAt": "2022-02-14T18:54:39.275Z",
                    "updatedAt": "2022-02-14T18:54:39.275Z",
                    "__v": 0,
                    "jobTitle": "Frontend Developer"
                }
            ]
        }
    ]
}

Using { $match: { $text: { $search: "Kolkata" } } } returns:

{
    "status": "success",
    "message": [
        {
            "metadata": [],
            "data": []
        }
    ]
}

Using { $match: { $or: [filters, { $text: { $search: "Kolkata" } }] } } returns:

MongoServerError: error processing query: ns=job-database.jobsTree: $or
    expired $eq false
    TEXT : query=Kolkata, language=english, caseSensitive=0, diacriticSensitive=0, tag=NULL
Sort: {}
Proj: {}
Collation: { locale: "simple" }
 planner returned error :: caused by :: Failed to produce a solution for TEXT under OR - other non-TEXT clauses under OR have to be indexed as well.
    at MessageStream.messageHandler (/home/deep/Personal/job-qna/node_modules/mongoose/node_modules/mongodb/lib/cmap/connection.js:467:30)
    at MessageStream.emit (events.js:375:28)
    at processIncomingData (/home/deep/Personal/job-qna/node_modules/mongoose/node_modules/mongodb/lib/cmap/message_stream.js:108:16)
    at MessageStream._write (/home/deep/Personal/job-qna/node_modules/mongoose/node_modules/mongodb/lib/cmap/message_stream.js:28:9)
    at writeOrBuffer (internal/streams/writable.js:358:12)
    at MessageStream.Writable.write (internal/streams/writable.js:303:10)
    at TLSSocket.ondata (internal/streams/readable.js:726:22)
    at TLSSocket.emit (events.js:375:28)
    at addChunk (internal/streams/readable.js:290:12)
    at readableAddChunk (internal/streams/readable.js:265:9) {
  ok: 0,
  code: 291,
  codeName: 'NoQueryExecutionPlans',
  '$clusterTime': {
    clusterTime: new Timestamp({ t: 1645314629, i: 1 }),
    signature: {
      hash: new Binary(Buffer.from("0fa1bccca48bef06c203ef8c5a16857f5cdf16af", "hex"), 0),
      keyId: new Long("7035651653462130689")
    }
  },
  operationTime: new Timestamp({ t: 1645314629, i: 1 })
}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source