I have an array of IDs that are populated in an array
.
I am trying to send an API get request to Strapi with filter as per below:
let listTagId = [];
tagOptions.map((tag) => {
if (inputValues[`${tag.nameTag}`]) {
listTagId.push(tag.id);
}
});
let filter = {
...cleanObject({
'tags.id': listTagId.length > 0 ? listTagId : null,
}
Where cleanObject
equals
function cleanObject(obj) {
let propNames = Object.getOwnPropertyNames(obj);
for (let i = 0; i < propNames.length; i++) {
var propName = propNames[i];
if (obj[propName] === null || obj[propName] === undefined) {
delete obj[propName];
}
}
return obj;
}
The filter then is used later with axios
which is calling to Strapi
async FIND(filter) {
try {
let query
if (filter) {
query = qs.stringify(filter)
}
let endpoint = `${this.apiEnpoint}${this.service}${query ? `?${query}` : ''}`
let { data } = await axios.get(endpoint,
{
headers: this.headers(this.getToken())
})
return { data }
} catch (error) {
return { error: this.getErrorMessage(error) }
}
}
The Tags are a collection which has a relationship to the API-OBJECT
. What I would want to achieve is to filter only those API-OBJECTs
which have all of the tags.id
included (tag.id1 and tag.id2...).
At the moment if I use the logic as per above (code) it uses OR logic, meaning it would retrieve back the results from the server if an object has ONE of the tags is in the listTagId
.
Example:
Extract from the console:
'GET /api-end-point/count?_where%5Bcategory_contains%5D=houses&_where%5Btags.id%5D%5B0%5D=60420fc8c4bed44584638dec&_where%5Btags.id%5D%5B1%5D=60420febc4bed44584638ded&_where%5Btags.id%5D%5B2%5D=6042151fbea9601908f2c774&_where%5Btags.id%5D%5B3%5D=60421520bea9601908f2c775&_where%5Btags.id%5D%5B4%5D=60421521bea9601908f2c776&_where%5Btags.id%5D%5B5%5D=60421522bea9601908f2c777&_where%5Btags.id%5D%5B6%5D=60421522bea9601908f2c778 (562 ms)'
I have tried to use tags.id_in
, but this gave the same results as now.
How should I change the query for the 'tags.id' in order to retrieve the desired elements?
I managed to go around this, by customizing the controller as it turns out Strapi does not have an AND
logic as I found. Though I don't like that this will use a lot of recourses as arrays are being updated and looped through fairly many times. If there are other suggestions please let me know.
What I am doing here is remove the limit so that I get all entities and then:
Getting all entities that have all the tags (using OR), and having the rest of the filters.
Once the size is reduced by something I am looping through the elements and finding the ones which have all of the tags ids.
I don't want to go through each and single one, so once I reached the limit I break out of the foreach loop.
"use strict";
const { sanitizeEntity } = require("strapi-utils");
module.exports = { async find(ctx) { let tags; let entities; let tagEntities = []; let limit; if (ctx.query?._limit) { limit = ctx.query._limit; delete ctx.query._limit; }
if (ctx.query?._where?.tags) {
tags = ctx.query._where.tags;
delete ctx.query._where.tags;
ctx.query._where["tags.id_in"] = tags;
}
if (ctx.query._q) {
entities = await strapi.services["custom-controller"].search(ctx.query);
} else {
entities = await strapi.services["custom-controller"].find(ctx.query);
}
tagEntities = [];
try {
entities.forEach((element) => {
if (limit <= 0) throw BreakException;
let newListId = [];
element.tags.forEach((tag) => newListId.push(tag?.id));
var result = tags?.every((val) => {
return newListId.indexOf(val) >= 0;
});
if (!tags) {
tagEntities.push(element);
limit--;
}
if (result) {
tagEntities.push(element);
limit--;
}
});
} catch (e) {}
return tagEntities.map((entity) =>
sanitizeEntity(entity, { model: strapi.models["custom-controller"] })
);
},
};