【问题标题】:How to do an ALL() or ANY() on a documents sub array如何在文档子数组上执行 ALL() 或 ANY()
【发布时间】:2026-01-11 03:40:01
【问题描述】:

只是了解 CosmosDB 的来龙去脉。我在 CosmosDB 中有以下测试文档:

[
    {
        "matchingID":123,
        "many":{
            "meta":"some data",
            "items":[
                {
                    "matchingID":921
                },
                {
                    "matchingID":123
                }
            ]
        }
    },
    {
        "matchingID":1337,
        "many":{
            "meta":"some more data",
            "items":[
                {
                    "matchingID":1337
                },
                {
                    "matchingID":1337
                }
            ]
        }
    },
    {
        "matchingID":9001,
        "many":{
            "meta":"all the datas",
            "items":[
                {
                    "matchingID":42
                },
                {
                    "matchingID":5318008
                }
            ]
        }
    }
]

请注意,这些是测试文档 - 实际文档在根项和子项中都有更多属性。每个项目在c.many.items 下都有一个子数组。这个子数组有一个属性,它可能匹配也可能不匹配它的根上的那个。我希望实现的是创建一个查询,允许我返回其子项全部匹配的项目,以及另一个将返回其中任何匹配项的查询。

例如 SELECT * FROM c WHERE ALL(c.many.items.matchingID) = c.matchingID 将返回第二个项目,因为所有子项目属性都匹配其父项:

 {
        "matchingID":1337,
        "many":{
            "meta":"some more data",
            "items":[
                {
                    "matchingID":1337
                },
                {
                    "matchingID":1337
                }
            ]
        }
    }

SELECT * FROM c WHERE ANY(c.many.items.matchingID) = c.matchingID 将返回第一个对象,至少有一个子项匹配属性


    {
        "matchingID":123,
        "many":{
            "meta":"some data",
            "items":[
                {
                    "matchingID":921
                },
                {
                    "matchingID":123
                }
            ]
        }
    }

【问题讨论】:

    标签: azure-cosmosdb


    【解决方案1】:

    我认为SELECT * FROM c WHERE ANY(c.many.items.matchingID) = c.matchingID 应该返回第一个和第二个对象。

    • 任何

    试试这个 sql:

    SELECT * FROM c where ARRAY_CONTAINS(c.many.items,{"matchingID":c.matchingID},true)
    

    结果如下:

     [
        {
            "matchingID": 123,
            "many": {
                "meta": "some data",
                "items": [
                    {
                        "matchingID": 921
                    },
                    {
                        "matchingID": 123
                    }
                ]
            }
        },
        {
            "matchingID": 1337,
            "many": {
                "meta": "some more data",
                "items": [
                    {
                        "matchingID": 1337
                    },
                    {
                        "matchingID": 1337
                    }
                ]
            }
        }
    ]
    
    • 全部

    我不能只使用一个sql。所以我查询了两次。

    第一个sql(获取matchingID数组):

    select value d.matchingID from (select c.matchingID,max(t.matchingID) as max,min(t.matchingID) as min from c join t in c.many.items group by c.matchingID) d where d.max = d.min and d.max = d.matchingID
    

    顺便说一下,如果你的matchingID不是唯一的,请在group by之后添加一个唯一的属性,比如group by c.matchingID,c.id

    第二条sql(获取对象):

    SELECT * FROM c where ARRAY_CONTAINS('first sql result',c.matchingID,true)
    

    希望这些对你有帮助。


    更新答案:

    这是我的测试 udf:

    function compareMatchID(matchingID,subArray){
        var result = subArray.every(function(a){
            return a.matchingID == matchingID;
        });
        return result;
    }
    

    这里是sql:

    SELECT * FROM c where udf.compareMatchID(c.matchingID,c.many.items)
    

    此 sql 与您的示例文档一起花费 4.4RU。

    【讨论】:

    • 谢谢。没错,在我的示例中, ANY 应该返回两个对象。在我的数据集上测试这些,ANY() 解决方案似乎相对简单。它的成本为 16RU。然而,ALL() 解决方案似乎真的很复杂——我可以看到它想要做什么,但至少在我的数据集上它的性能很差,而且成本 > 1200 RU。我会再给这篇文章几天,看看是否还有其他可能的解决方案,否则我可能必须向我的many 对象添加一个属性,例如:"any": true, "all": false,因为这都是预先计算的,无论如何都是静态数据
    • 另外,我想知道是否可以为 ALL 使用 UDF?
    • 你可以试试。但是UDF没有访问上下文对象的权限,所以你需要将你的文档传递给UDF,然后循环子数组并比较matchingID。我担心性能UDF 可能不会更好,而且成本也很昂贵。我认为您可以通过在客户端使用代码而不是使用 UDF 来更好地处理它。
    • 我更新了我的答案,你可以试试。你的例子比select * from c花费更多Ru。如果你不想为你的许多对象添加属性,你可以获取所有数据并通过代码处理。