Search within relation content type

So I managed to implement a hacked-together solution on the Backend.
Whether this is the correct way of solving this issue, I don’t know. In fact, I doubt it.
Best I could come up with.

Problem:

Extend the find/search function to search with relational documents in MongoDB


Solution:

  1. Retrieve populated documents. (Main document and their relational documents)
  2. Search through the array of documents and store result.
  3. Return the result as a response.
// in services file - /api/onts/services/onts.js

const pop = [
  {
    path: "address_unit",
    populate: {
      path: "address_complex",
    },
  },
  {
    path: "services",
    populate: {
      path: "vlan",
    },
  },
];

module.exports = {
  customFind: async (params, populate) => {
    let results;
    let filteredResults;
    results = await strapi.query("onts").find(null, pop);  // Step 1
    filteredResults = searchArrayOfObjects(results, params);  // Step 2
    return filteredResults;  // Step 3
  },
};
// in controllers file - /api/onts/controllers/onts.js
module.exports = {
  customFind: async (ctx) => {
    let result;
    result = await strapi.services.onts.customFind(ctx.params.find);
    return result;
  },
};
// in routes file - /api/onts/config/routes.json

{
  "routes": [
    {
      "method": "GET",
      "path": "/onts/:find",
      "handler": "onts.customFind",
      "config": {
        "policies": []
      }
    },
    ... //other routes
 ]
}

For those interested in knowing what search function I used in Step 2 searchArrayOfObjects(results, params), here is the code.

function searchSingleObject(object, text) {
  let flag;
  for (let key in object) {
    if (object[key] !== null) {
      if (typeof object[key] === "object") {
        if (object[key].length > 0 || object[key].length !== undefined) {
          flag = searchArrayOfObjects(object[key], text);
        }
        flag = searchSingleObject(object[key], text);
        if (flag) break;
      } else {
        flag = false;
        flag =
          object[key].toString().toLowerCase().indexOf(text.toLowerCase()) > -1;
        if (flag) break;
      }
    }
  }

  return flag;
}

function searchArrayOfObjects(objectList, text) {
  if (undefined === text || text === "" || text === undefined)
    return objectList;
  const res = objectList.filter((object) => {
    return searchSingleObject(object, text);
  });
  return res;
}

Anyway, it works.
Please let me know if there are better solutions available.

1 Like