【问题标题】:CosmosDb Sql query that matches common values in array between documentsCosmosDb Sql 查询匹配文档之间数组中的公共值
【发布时间】:2020-01-13 12:28:22
【问题描述】:

我正在使用 Cosmos DB,我想编写一个 SQL 查询,该查询将匹配基于 id 的文档数组中的公共值。

详细来说,假设您有以下三个文件:

{
        "id": "2ECF4568-CB0E-4E11-A5CD-1206638F9C39",
        "entityType": "ServiceInformationFacility",
        "facilities": [
            {
                "id": "6F706BA3-27AD-45B8-9831-A531E37C4C17",
                "facilityName": "Kat Service Center",
                "phoneNumber": "9879561234"

            },
            {
                "id": "7F706BA3-27AD-45B8-9831-A531E37C4C17",
                "facilityName": "Honda Service Center",
                "phoneNumber": "9879561234"

            }]

    },
    {
        "id": "3ECF4568-CB0E-4E11-A5CD-1206638F9C39",
        "entityType": "ServiceInformationFacility",
        "facilities": [
            {
                "id": "8F706BA3-27AD-45B8-9831-A531E37C4C17",
                "facilityName": "Hyundai Service Center",
                "phoneNumber": "9879561234"

            },
            {
                "id": "7F706BA3-27AD-45B8-9831-A531E37C4C17",
                "facilityName": "Honda Service Center",
                "phoneNumber": "9879561234"

            }]

    },
    {
        "id": "6ECF4568-CB0E-4E11-A5CD-1206638F9C39",
        "entityType": "ServiceInformationFacility",
        "facilities": [
            {
                "id": "8F706BA3-27AD-45B8-9831-A531E37C4C17",
                "facilityName": "Hyundai Service Center",
                "phoneNumber": "9879561234"

            },
            {
                "id": "7F706BA3-27AD-45B8-9831-A531E37C4C17",
                "facilityName": "Honda Service Center",
                "phoneNumber": "9879561234"
            } ]
    }

我想编写一个查询,返回所有基于 id 的公共设施。这意味着当传递 Id 列表时,应该显示给定 Id 中存在的设施(不是要么或)。 所以在上面的集合中,它应该只返回 "facilityName": "Honda Service Center" 通过传递参数 id("2ECF4568-CB0E-4E11-A5CD-1206638F9C39"," 3ECF4568-CB0E-4E11-A5CD-1206638F9C39","6ECF4568-CB0E-4E11-A5CD-1206638F9C39")。

到目前为止我已经尝试过:

SELECT q.facilityName  FROM c
join q in c.facilities
where c.id in('6ECF4568-CB0E-4E11-A5CD-1206638F9C39','2ECF4568-CB0E-4E11-A5CD-1206638F9C39')AND c.entityType = 'ServiceInformationFacility'

它给了我所有的设施名称,但我只需要上述文件中常见的设施,即“facilityName”:“Honda Service Center”。

提前致谢

【问题讨论】:

    标签: azure-cosmosdb azure-cosmosdb-sqlapi


    【解决方案1】:

    它给了我所有的设施名称,但我只需要设施 上述文件中常见的就是“facilityName”:“Honda Service 中心”。

    我现在可能明白你的意思了。但是,恐怕这在 cosmos sql 中是不可能的。我尝试计算facilitiesName 的出现次数交叉文档并获得最符合您需要的解决方案。

    sql:

    SELECT count(c.id) as cnt, f.facilityName from c 
    join f in c.facilities
    where array_contains(['6ECF4568-CB0E-4E11-A5CD-1206638F9C39','2ECF4568-CB0E-4E11-A5CD-1206638F9C39'],c.id,true)
    AND c.entityType = 'ServiceInformationFacility'
    group by f.facilityName
    

    输出:

    然后我尝试用一​​些 subquery 扩展它,但没有运气。所以我建议使用存储过程来完成下一项工作。主要目的是循环上面的结果并判断cnt是否等于[ids array].length


    更新存储过程代码的答案:

    @idArray 的输入参数:["6ECF4568-CB0E-4E11-A5CD-1206638F9C39","2ECF4568-CB0E-4E11-A5CD-1206638F9C39"]

    Sp代码:

    function sample(idArray) {
        var collection = getContext().getCollection();
    
        var length = idArray.length;
    
        var sqlQuery = {
            "query":  'SELECT count(c.id) as cnt, f.facilityName from c join f in c.facilities '+
            'where array_contains( @idArray,c.id,true) ' +
            'AND c.entityType = "ServiceInformationFacility" group by f.facilityName',
            "parameters": [
                {"name": "@idArray", "value": idArray}
            ]
        }
    
        // Query documents and take 1st item.
        var isAccepted = collection.queryDocuments(
            collection.getSelfLink(),
            sqlQuery,
        function (err, feed, options) {
            if (err) throw err;
            if (!feed || !feed.length) {
                var response = getContext().getResponse();
                response.setBody('no docs found');
            }
            else {
                var response = getContext().getResponse();
                var returenArray = [];
                for(var i=0;i<feed.length;i++){                
                    if(feed[i].cnt==length)
                        returenArray.push(feed[i])
                }
    
                response.setBody(returenArray);
            }
        });
    
        if (!isAccepted) throw new Error('The query was not accepted by the server.');
    }
    

    输出:

    【讨论】:

    • 我不想在查询中硬编码设施名称。它应该根据 Ids 显示数组中的公共设施名称。
    • @Triptychauhan 如果我再次误解了您的要求,请告诉我。您想获取设施名称并删除所有重复的项目,对吗?只需在你的 sql 中使用 distinct operator。
    • 让我解释一下。上面提到了三个文件,在这三个文件中我需要facilityName,它们是通用的并且存在于所有文件中。如果你看到三个文档中只有本田服务中心在所有文档数组中是通用的。与sql中的intersect或inner join相同,以获得匹配的记录。是否有可能实现这一点?
    • @Triptychauhan 对我之前的误解深表歉意,请参考我的最新回答,如有任何疑问,请告诉我。
    • 是的,我看到了类似的帖子。我的分区键是文档中提到的“entityType”,当我在执行分区键参数和输入参数 Ids 时将分区键值“ServiceInformationFacility”作为字符串传递时sp,我得到“找不到文档”作为输出。
    猜你喜欢
    • 2020-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-22
    • 2021-03-18
    • 1970-01-01
    相关资源
    最近更新 更多