Complex combination of AND and OR in strapi (version 4) filtering - strapi

Hi I want to apply a filter to the strapi api with a combination of AND and OR but I can't seem to get it working.
Situation:
I want to filter on a situation like this
(
(tag OR tag2 OR tag3) AND
(
(title CONTAINSI TEXT_FILTER_HERE) OR
(body CONTAINSI TEXT_FILTER_HERE) OR
(introduction CONTAINSI TEXT_FILTER_HERE)
)
)
(note that I have abbreviated the tags as that should also be a containsi)
I have tried something like the link below and many others, but this example below will make all of them an OR situation, and I will find too many entries.
{{host}/api/blog?sort=publishedAt%3Adesc
&populate=Tags.tags&populate=Image
&pagination[page]=1
&pagination[pageSize]=25
&locale=en
&filters[$or][4][Tags][tags][Tag][$containsi]=TAG1
&filters[$or][6][Tags][tags][Tag][$containsi]=TAG2
&filters[$or][8][Tags][tags][Tag][$containsi]=TAG3
&filters[$or][3][Tags][tags][Tag][$containsi]=TAG4
&filters[$or][5][Tags][tags][Tag][$containsi]=TAG5
&filters[$or][7][Tags][tags][Tag][$containsi]=TAG6
&filters[$or][0][title][$containsi]=FILTER_TEXT_HERE
&filters[$or][2][body][$containsi]=FILTER_TEXT_HERE
&filters[$or][1][introduction][$containsi]=FILTER_TEXT_HERE
(made it multiline for readability)
Is it possible to this in strapi?
I can get it to work in an multiple OR situation with just one (1) AND, but not with ((or or) AND (or or)):
...
&filters[$or][4][Tags][tags][Tag][$containsi]={{tag1}}
&filters[$or][6][Tags][tags][Tag][$containsi]={{tag2}}
&filters[$or][8][Tags][tags][Tag][$containsi]={{tag3}}
&filters[$or][3][Tags][tags][Tag][$containsi]={{tag4}}
&filters[$or][5][Tags][tags][Tag][$containsi]={{tag5}}
&filters[$or][7][Tags][tags][Tag][$containsi]={{tag6}}
&filters[$and][0][title][$containsi]={{filter}}
or
...
&filters[$or][4][Tags][tags][Tag][$containsi]={{tag1}}
&filters[$or][6][Tags][tags][Tag][$containsi]={{tag2}}
&filters[$or][8][Tags][tags][Tag][$containsi]={{tag3}}
&filters[$or][3][Tags][tags][Tag][$containsi]={{tag4}}
&filters[$or][5][Tags][tags][Tag][$containsi]={{tag5}}
&filters[$or][7][Tags][tags][Tag][$containsi]={{tag6}}
&filters[title][$containsi]={{filter}}
Any help will be appreciated

I actually think I have found the answer. Could not find it anywhere in the documentation (https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/filtering-locale-publication.html#complex-filtering)
{{host}}/api/blog?sort=publishedAt%3Adesc
&populate=Tags.tags
&populate=Image
&pagination[page]=1
&pagination[pageSize]=25
&locale=en
&filters[$and][0][$or][0][title][$containsi]={{filter}}
&filters[$and][0][$or][1][introduction][$containsi]={{filter}}
&filters[$and][0][$or][2][body][$containsi]={{filter}}
&filters[$and][1][$or][0][Tags][tags][Tag][$containsi]={{tag1}}
&filters[$and][1][$or][1][Tags][tags][Tag][$containsi]={{tag2}}
&filters[$and][1][$or][2][Tags][tags][Tag][$containsi]={{tag3}}
&filters[$and][1][$or][3][Tags][tags][Tag][$containsi]={{tag4}}
&filters[$and][1][$or][4][Tags][tags][Tag][$containsi]={{tag5}}
&filters[$and][1][$or][5][Tags][tags][Tag][$containsi]={{tag6}}
Note the [NUMBER] sections grouping the ANDs and OR's ...
Once you know it, it looks logical :-)

Related

In Google Sheets, How do I sumif(s) over a comma separated list in string?

In our schools, we have books of the same title by the same author but different ISBN #s. I am working on an inventory list so that we can scan the different ISBNs and then find out what is on hand for a title.
Here is my working spreadsheet demo. The live version will be separated (columns A-D by data that comes in on another sheet (possibly by Google Forms) and a separate sheet (F-J) that does all the math. For convenience / testing, they are all on one sheet.
Essentially, in column F, I would like to sum all the quantities in A where the ISBN's in C match any of the values of G and place it in F.
The formula I am using in F doesn't seem to completely work:
=SUMIF(C:C,arrayformula(split(G2,",")),A:A)
It captures the first match but ignores / doesn't loop over the rest. I have looked at Sumifs and Match and I cannot seem to get any closer with the syntax. I would greatly appreciate if anyone can help me solve this dilemma.
Additionally, I know how to do this with a custom script but I need to avoid that as end users break things for one reason or another and I can't handle the debugging load the way this could possibly be deployed.
Thanks in advance for anyone willing to take a look at this!
~Allan
Try in F2
=sum(query(A:D,"select A where C matches '"& textjoin("|",,split(G2,",")) &"' ",0))
delete everything in F2:F & J2:J and use F2:
=INDEX(IF(G2:G="",,MMULT(IFERROR(VLOOKUP(SPLIT(G2:G, ","), {C:C, A:A}, 2, ), 0),
SEQUENCE(COLUMNS(SPLIT(G2:G, ",")), 1, 1, ))))
in J2 use:
=ARRAYFORMULA(IF(G2:G="",,F2:F*I2:I))

DMQL2 Query Syntax for PHRets v2 Seach() to include filter arguments?

(It's been a while since I've been here.)
I've been using the first version of PHRets v1 for years, and understood it well enough to get by, but now I'm trying to understand the advantages of v2.6.2. I've got it all installed and the basics are working fine. My issues are pretty much with comprehending fine points of query syntax that goes into the rets=>Search() statement. (I'm much more familiar with SQL statements). Specifically, I'd like to have a query return a list of properties, EXCLUDING those which already have the status of "Sold".
Here's where I am stuck: If I start with this
`$results = $rets->Search('Property', 'A','*',['Select' => 'LIST_8,LIST_105,LIST_15,LIST_19,listing_office_shortid']);`
That works well enough. BUT I'd like to fit in a filter like:
"LIST_15 != Sold", or "NOT LIST_15=Sold"...something like that. I don't get how to fit/type that into a PHRets Search().
I like PHRets but it is so hard to find well-organized/complete documentation about specific things like this. Thanks in advance.
As in my comment above I've figured out that the filter goes in the third argument position ('*', as in the original question). The tricky thing was having to find a specific "sold" code for each class of properties and placing it in that position like so: '(LIST_15=~B4ZIT1Y75TZ)', (notice the =~ combination of characters that means "does not equal" in this context). I've found the code strings for each of the property types (not clear WHY they would need to be unique for each type of property: "Sold" is Sold for any type, after all) but the correct code for a single-family residential property (type 'A' ...at least for the MLS in which I have to search is:
$results = $rets->Search('Property', 'A','(LIST_15=~B4ZIT1Y75TZ)',['Select' => 'LIST_8,LIST_105,LIST_15,LIST_19,listing_office_shortid']);
(again, the code to go with LIST_15 will be different for the different types of properties.) I think there is a better answer that involves more naturalistic language, but this works and I guess I will have to be satisfied with it for now. I hope this is of some use to anyone else struggling with this stuff.

How to ignore "stop words" while sorting in MarkLogic?

Is there any way to ignore "stop words" while sorting.
For example:
I have words like
dixit
singla
the marklogic
On sorting in descending order the result should be
singla, the marklogic, dixit
As in the above example the is ignored.
Any way to achieve this?
Update:
Stop word can occur at any place.
for example
the MarkLogic
MarkLogic is the best
the MarkLogic is awesome
while sorting should not consider any stop word in the text.
Above is just a small example to describe the problem.
In actual I am using search:search API.
For sorting, I am using sort-order search options.
The element on which I have to perform sorting is dynamic. There are approx 30-35 elements.
Is there any way to customize the collation at this level like to configure some words (stop words) which will be ignored while sorting.
There is no standard collation URI that is going to do this for you (at least none that I've ever seen). You can do it dynamically, of course, by sorting on the result of a function invocation, but if you want it done efficiently at scale (and available to search:search), then you need to materialize the sortable string into your document. I've often done this as an attribute on the element:
<title sortable="Great Gatsby, The">The Great Gatsby</title>
Then you put a range index on the title/#sortable attribute.
You can also use the "envelope pattern" where materialized metadata like this is maintained in its own section of the document with the original kept in its own section. For things like this, I think it's a bit more elegant to decorate the elements directly, to keep the context.
If I understand your question correctly you're trying to get rid of the definite article when sorting your result-set.
In order to do this you need to use some additional functions and create a 'sort' criteria. My solution would look like this (I'm also including some sample documents so that you can test this just by copy-pasting):
(:
xdmp:document-insert("/peter.xml", <person><firstName>Peter</firstName><lastName>O'Toole</lastName><age>60</age></person>);
xdmp:document-insert("/john.xml", <person><firstName>John</firstName><lastName>Adams</lastName><age>18</age></person>);
xdmp:document-insert("/simon.xml", <person><firstName>Simon</firstName><lastName>Petrov</lastName><age>22</age></person>);
xdmp:document-insert("/mark.xml", <person><firstName>Mark</firstName><lastName>the Lord</lastName><age>25</age></person>);
:)
for $person in /person
let $sort := fn:reverse(fn:tokenize($person/lastName, ' '))[1]
order by $sort
(: return $person :)
return $person/lastName/text()
Notice that now the sort order is going to be
- Adams
- the Lord
- O'Toole
- Petrov
I hope this will help.

LINQ - OR two SqlMethods.Like clauses

I need to OR two SqlMethods.Like statements in LINQ, and I'm not sure how to accomplish it (or if it's the right way to go about it).
I've got vendor ID and vendor name fields, but I've only got a generic vendor search that allows a user to search for a vendor based on their name or ID. I also allow wildcards in the search, so I need to find vendors whose ID or name is like the user's input.
I want to do something like below, but obviously it's not correct. (EDIT: It does work as written.)
results = results.Where(p => SqlMethods.Like(p.VendorId, inputVendor.Replace("*", "%") ||
SqlMethods.Like(p.VendorName, inputVendor.Replace("*", "%"));
Background: I add where statements depending on the search parameters entered by the user, hence the results = results.Where part.
Any help would be appreciated!
It's not clear to me why this is "obviously" not correct. Presumably it's not working, otherwise you wouldn't have posted, but it's not obvious how it's not working.
I would suggest performing the replacement before the query, like this:
string vendorPattern = inputVendor.Replace("*", "%");
But then I'd expect this to work:
results = results.Where(p => SqlMethods.Like(p.VendorId, vendorPattern) ||
SqlMethods.Like(p.VendorName, vendorPattern));
Of course you're limited to where wildcards can appear in a SQL LIKE query, but that's a separate problem. (I'm not sure of the behaviour offhand if it's not at the start or end.)
If that doesn't help, please update the question with what happens when you try this.

using xpath to obtain complex values

Given the following, I'd like to extract VarVal1, VarVa5 and VarText where FixedVals are, well, fixed :)
<TypeA Attr1="VarVal1">
<TypeB Attr2="FixedVal2">
<TypeC Attr3="FixedVal3">
<TypeD Attr4="FixedVal4" Attr5="VarVal5">
VarText
</TypeD>
</TypeC>
</TypeB>
</TypeA>
Notice that the big problem for me is that the context is important. I want the complete pattern. There may be other TypeA nodes, but I'm not interested in their values unless they're followed by
<TypeB Attr2="FixedVal2">
<TypeC Attr3="FixedVal3">
<TypeD Attr4="FixedVal4" Attr5="VarVal5">
VarText
</TypeD>
</TypeC>
</TypeB>
In other words, what I'm interested in is a set of tripletts, each of them in the form of (VarVal1, VarVal5, VarText)
These XPath expressions:
//TypeA
[TypeB[#Attr2="FixedVal2"]
/TypeC[#Attr3="FixedVal3"]
/TypeD[#Attr4="FixedVal4"]]
/#Attr1
Then those already posted:
//TypeA
/TypeB[#Attr2="FixedVal2"]
/TypeC[#Attr3="FixedVal3"]
/TypeD[#Attr4="FixedVal4"]
/#Attr5
And
//TypeA
/TypeB[#Attr2="FixedVal2"]
/TypeC[#Attr3="FixedVal3"]
/TypeD[#Attr4="FixedVal4"]
You could also combine them with | union set operator. But depending on the host language, you should better select the TypeA elements you want (first expression with out last /#Attr1 part) and then query each of those to extract the remaining values.
I think you need a couple of queries for this (could be wrong though)
for VarVal1
//TypeA/#Attr1
for VarVal5
//TypeA
/TypeB[#Attr2="FixedVal2"]
/TypeC[#Attr3="FixedVal3"]
/TypeD[#Attr4="FixedVal4"]
/#Attr5
Think these should do the trick
EDIT - missed VarText!
//TypeA
/TypeB[#Attr2="FixedVal2"]
/TypeC[#Attr3="FixedVal3"]
/TypeD[#Attr4="FixedVal4"]

Resources