[SERVER-73074] Add splitMatchExpressionBy test cases for $jsonSchema.required expression Created: 19/Jan/23  Updated: 29/Oct/23  Resolved: 03/Feb/23

Status: Closed
Project: Core Server
Component/s: None
Affects Version/s: None
Fix Version/s: 6.3.0-rc0

Type: Improvement Priority: Major - P3
Reporter: Charlie Swanson Assignee: Yoon Soo Kim
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Depends
is depended on by SERVER-73073 Refactor existing time-series deletes... Closed
Assigned Teams:
Storage Execution
Backwards Compatibility: Fully Compatible
Participants:

 Description   

In SERVER-73073 we plan to use this utility to replace the logic here. I'm not sure if it can out of the box, but at the very least we could use some tests - I didn't see any in expression_algo_test.cpp.



 Comments   
Comment by Githook User [ 03/Feb/23 ]

Author:

{'name': 'Yoonsoo Kim', 'email': 'yoonsoo.kim@mongodb.com', 'username': 'yun-soo'}

Message: SERVER-73074 Add splitMatchExpressionBy test cases for $jsonSchema.required expression
Branch: master
https://github.com/mongodb/mongo/commit/a073b665cb0299080469bce2dd4f2ffdaa8806d6

Comment by Mohammad Dashti (Inactive) [ 02/Feb/23 ]

One of the issues is related to improving the implementation of the isIndependentOf function. This one calls the hasOnlyRenameableMatchExpressionChildren function, which fails on this line (as all jsonSchema-related expression types are categorized as "Other". It seems that the lack of support for the jsonSchema expressions was deliberate at the time of implementing expression::splitMatchExpressionBy. Nevertheless, as you mentioned, there might be a subset of examples with jsonSchema that are supported out-of-the-box.

Comment by Mohammad Dashti (Inactive) [ 02/Feb/23 ]

yoonsoo.kim@mongodb.com Here is the test I used to come up with the result of jsonSchema is currently not supported in expression_algo::splitMatchExpressionBy:

TEST(SplitMatchExpressionForJsonSchema, CheckSupportForJsonSchema1) {
    BSONObj matchPredicate = fromjson(R"({
        $jsonSchema: {
            "title": "Record of employee",
            "description": "This document records the details of an employee",
            "type": "object",
            "properties": {
                "_id": {
                    "description": "A unique identifier for an employee",
                    "type": "number"
                },
                "name": {
                    "description": "name of the employee",
                    "type": "string",
                    "minLength": 2
                },
                "age":
                    {"description": "age of the employee", "type": "number", "minimum": 16},
                "hobbies": {
                    "description": "hobbies of the employee",
                    "type": "object",
                    "properties": {
                        "indoor": {
                            "type": "array",
                            "items": {"description": "List of hobbies", "type": "string"},
                            "minItems": 1,
                            "uniqueItems": true
                        },
                        "outdoor": {
                            "type": "array",
                            "items": {"description": "List of hobbies", "type": "string"},
                            "minItems": 1,
                            "uniqueItems": true
                        }
                    },
                    "required": ["indoor", "outdoor"]
                }
            },
            "required": ["_id", "name", "age", "hobbies"],
            "additionalProperties": false
        }
    })");
    boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
    StatusWithMatchExpression status =
        MatchExpressionParser::parse(matchPredicate, std::move(expCtx));
    ASSERT_OK(status.getStatus());
 
    auto&& [splitUp, residual] =
        expression::splitMatchExpressionBy(std::move(status.getValue()), {"y"}, {});
    std::cout << "splitUp : " << (splitUp ? splitUp->toString() : "NULLLL") << std::endl;
    std::cout << "residual : " << (residual ? residual->toString() : "NULLLL") << std::endl;
}
 
TEST(SplitMatchExpressionForJsonSchema, CheckSupportForJsonSchema2) {
    BSONObj matchPredicate = fromjson(R"({
        $jsonSchema: {
            "title": "Record of employee",
            "description": "This document records the details of an employee",
            "type": "object",
            "required": ["_id", "name", "age", "hobbies"],
            "additionalProperties": false
        }
    })");
    boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
    StatusWithMatchExpression status =
        MatchExpressionParser::parse(matchPredicate, std::move(expCtx));
    ASSERT_OK(status.getStatus());
 
    auto&& [splitUp, residual] =
        expression::splitMatchExpressionBy(std::move(status.getValue()), {"y"}, {});
    std::cout << "splitUp : " << (splitUp ? splitUp->toString() : "NULLLL") << std::endl;
    std::cout << "residual : " << (residual ? residual->toString() : "NULLLL") << std::endl;
}

Here is the output:

splitUp : { $and: [ { $and: [ { name: { $_internalSchemaMinLength: 2 } }, { age: { $gte: 16 } } ] }, { $and: [ { _id: { $exists: true } }, { age: { $exists: true } }, { hobbies: { $exists: true } }, { name: { $exists: true } } ] } ] }
residual : { $and: [ { $and: [ { _id: { $_internalSchemaType: [ "number" ] } }, { name: { $_internalSchemaType: [ 2 ] } }, { age: { $_internalSchemaType: [ "number" ] } }, { $and: [ { hobbies: { $_internalSchemaObjectMatch: { $and: [ { $and: [ { indoor: { $_internalSchemaMinItems: 1 } }, { indoor: { $_internalSchemaUniqueItems: true } }, { indoor: { $_internalSchemaAllElemMatchFromIndex: [ 0, { $and: [ { i: { $_internalSchemaType: [ 2 ] } } ] } ] } }, { indoor: { $_internalSchemaType: [ 4 ] } } ] }, { $and: [ { outdoor: { $_internalSchemaMinItems: 1 } }, { outdoor: { $_internalSchemaUniqueItems: true } }, { outdoor: { $_internalSchemaAllElemMatchFromIndex: [ 0, { $and: [ { i: { $_internalSchemaType: [ 2 ] } } ] } ] } }, { outdoor: { $_internalSchemaType: [ 4 ] } } ] } ] } } }, { hobbies: { $_internalSchemaObjectMatch: { $and: [ { indoor: { $exists: true } }, { outdoor: { $exists: true } } ] } } }, { hobbies: { $_internalSchemaType: [ 3 ] } } ] } ] }, { $_internalSchemaAllowedProperties: { properties: [ "_id", "age", "hobbies", "name" ], namePlaceholder: "i", patternProperties: [], otherwise: { $alwaysFalse: 1 } } } ] }
 
splitUp : { $and: [ { _id: { $exists: true } }, { age: { $exists: true } }, { hobbies: { $exists: true } }, { name: { $exists: true } } ] }
residual : { $_internalSchemaAllowedProperties: { properties: [], namePlaceholder: "i", patternProperties: [], otherwise: { $alwaysFalse: 1 } } }

It's expected for residual to be empty, but it is not the case in either of these tests.

Comment by Yoon Soo Kim [ 01/Feb/23 ]

It sounds like that the logic that we want to replace can be achieved by splitMatchExpressionBy(...,isOnlyDependentOn). Adding test cases. The $jsonSchema expression of interest is $jsonSchema: {required: [field]} and it's translated into {field: {$exists: true}}.

Comment by Mohammad Dashti (Inactive) [ 30/Jan/23 ]

jsonSchema is currently not supported in expression_algo::splitMatchExpressionBy.

Generated at Thu Feb 08 06:23:34 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.