turkraft / springfilter

Dynamically filter JPA entities and Mongo collections with a user-friendly query syntax. Seamless integration with Spring APIs. Star to support the project! ⭐️
https://turkraft.com/springfilter
216 stars 35 forks source link

Draft: Filtering Collections #389

Open Elias23 opened 2 months ago

Elias23 commented 2 months ago

Based on the described solution in the issue thread resolves turkraft/springfilter#334. Have not yet implemented a fix for the Date problem.

torshid commented 2 months ago

There are some serious changes in the original solution provided by @zhenyabodukhin. Would like to know how these performed since then. Unit tests will make the thing perfect I guess.

zhenyabodukhin commented 2 months ago

@torshid Only wrap arrays if there exists in filter not enough. You should combine them like this: "$anyElementTrue": { "$map": { "input": { "$ifNull": [ "$tasks", [] ] }, "in": { "$anyElementTrue": { "$map": { "input": { "$ifNull": [ "$$this.groupRecipient", [] ] }, "in": { "$and": [ { "$eq": [ "$$this.tenantId", { "$uuid": "4ec6e247-895f-47fa-b427-cecf2ac0f54f" } ] }, { "$eq": [ "$$this.groupName", "PLATFORM_OPERATOR" ] }, { "$anyElementTrue": { "$map": { "input": { "$ifNull": [ "$$this.roles", [] ] }, "in": { "$and": [ { "$isArray": [ [ "ORDER_MANAGER" ] ] }, { "$in": [ "$$this", [ "ORDER_MANAGER" ] ] } ] } } } } ] } } } } } }

I added cache to TransformerUtils, but its not works if you have similar paths in filter (only first will be applied). I can post my solution if it necessary.

zhenyabodukhin commented 2 months ago

@torshid Check last commit. https://github.com/zhenyabodukhin/springfilter/tree/bug/nested-search-mongo

zhenyabodukhin commented 2 months ago

For example “tasks.text: ‘value1’ and tasks.text: ‘value2’” will not work. In this case you can refactor like this “tasks.text in [‘value1’, ‘value2’]” and it will work. But if we have like this “tasks.date:> ‘value1’ and tasks.date:< ‘value2’” will not work and this is a problem. In my project we escape this case, but for you this is bad solution :) When i sad “combine” i mean combine by arrays path.

zhenyabodukhin commented 2 months ago

I guess problem with same paths in filter is appear because i cache nodes and in wrapArrays methods i invokes method transform(), so again invokes wrapArrays and cache not work properly. So i added processedPath to solve this problem, as a result we have issue with same paths. I think if we has opportunity not to use transform() in arrayPaths() this problem will be solved.

Elias23 commented 2 months ago

In my case I don't have nested Collections, which simplifies the issue for me. I added a post-processing stage to the filter generation, which flattens out nested and and or. Afterward, I merge the paths in the same and/or block if the mapping matches. I added some simple tests.

Elias23 commented 2 months ago

Not sure how to provide an integration test like proof that it works for simple collections. Here is an example: filter: active=false and groupMemberships.entryDate= '1951-12-03T00:00:00Z' and groupMemberships.leavingDate= '1955-12-04T00:00:00Z' result:

{
    "$expr": {
        "$and": [
            {
                "$eq": [
                    "$active",
                    false
                ]
            },
            {
                "$anyElementTrue": {
                    "$map": {
                        "input": {
                            "$ifNull": [
                                "$groupMemberships",
                                []
                            ]
                        },
                        "as": "this",
                        "in": {
                            "$and": [
                                {
                                    "$eq": [
                                        "$$this.entryDate",
                                        {
                                            "$date": {
                                                "$numberLong": "-570585600000"
                                            }
                                        }
                                    ]
                                },
                                {
                                    "$eq": [
                                        "$$this.leavingDate",
                                        {
                                            "$date": {
                                                "$numberLong": "-444268800000"
                                            }
                                        }
                                    ]
                                }
                            ]
                        }
                    }
                }
            }
        ]
    }
}