【问题标题】:CosmosDb complex sortingCosmosDb 复杂排序
【发布时间】:2021-02-03 16:07:24
【问题描述】:

我有一个 CosmosDb 集合,其中包含如下所示的文档:

{
  "status": [0/1]
  "someFlag": [true/false]
  "score": 24.0
}

我想用一些复杂的排序来查询这个集合:

  • 首先我想获取 status 为 1 且 someFlag 为 true 的文档
  • 二,status为1,someFlag为false
  • 三、status为0且someFlag为true
  • 四、status为0且someFlag为false

所以我有 4 个部分,我希望在每个部分中从最高分开始排序。 我可以使用单个 SQL 查询或使用 .NET 客户端对数据库进行单个请求以某种方式做到这一点吗?

【问题讨论】:

  • 所以...这似乎更多地是关于过滤,在WHERE 子句中(您可以使用ORAND 拥有多个过滤器)。我建议发布您的 SQL 查询,以及您遇到问题的地方。
  • 这与过滤无关,我想获取所有记录并像我描述的那样对它们进行排序。我能想到解决这个问题的唯一方法是进行 4 个查询并连接结果,但我想知道是否有办法在单个查询中做到这一点。
  • 对 - 我在 where 子句中向您指出了 orand,它们旨在满足您的要求。将其与order by 结合使用。这也在 SQL API 文档中。我建议尝试让查询正常工作,然后编辑您的问题以显示您的特定输出问题、错误等。
  • 所以我认为这里的混淆是你没有提供你想要的输出应该是什么的例子(这就是为什么,在我原来的评论中,我要求澄清)。如果您尝试在单个查询中创建多个排序的文档列表,那么不,您不能在单个查询中执行此操作。我提供了一个答案,但它假设您需要在一个联合中进行四个查询。
  • @Husker 我帮你发布答案。这可能对其他社区成员有益。

标签: azure azure-cosmosdb azure-cosmosdb-sqlapi


【解决方案1】:

使用以下 SQL 和 ut 所需的复合索引与这三个字段一起工作。

SELECT * 
FROM c 
WHERE c.Status = 0 OR c.Status = 1 
ORDER BY c.Status DESC, c.SomeFlag DESC, c.Score DESC

【讨论】:

    【解决方案2】:

    我只是想补充一些信息。

    如果你有这样的收藏

    [{"status": 0,"someFlag": true,"score": 24},{"status": 0,"someFlag": false,"score": 23},
    {"status": 1,"someFlag": false,"score": 20},{"status": 1,"someFlag": true,"score": 28},
    {"status": 0,"someFlag": false,"score": 31},{"status": 0,"someFlag": true,"score": 33},
    {"status": 1,"someFlag": false,"score": 17},{"status": 1,"someFlag": true,"score": 15}]
    

    而你想在 cosmosbd 中用一条 sql 得到这样的查询结果:

    [{"status": 0,"someFlag": true,"score": 24},{"status": 0,"someFlag": true,"score": 33},
    {"status": 0,"someFlag": false,"score": 23},{"status": 0,"someFlag": false,"score": 31},
    {"status": 1,"someFlag": true,"score": 15},{"status": 1,"someFlag": true,"score": 28},
    {"status": 1,"someFlag": false,"score": 17},{"status": 1,"someFlag": false,"score": 20}]
    

    我认为这是不可能的。我试过这样的sql,但失败了。正如你所说,你可以使用 4 个查询部分来获取结果,所以剩下的任务是连接这 4 个部分,所以我们需要使用 array_concat,但它在 cosmosdb 中确实不支持。至少,到现在为止,我还没有找到任何函数来实现它。

    SELECT ARRAY_CONCAT((SELECT aa.status,aa.someFlag,aa.score FROM c as aa where aa.status=0 and aa.someFlag=true order by aa.score),
    (SELECT bb.status,bb.someFlag,bb.score FROM c as bb where bb.status=1 and bb.someFlag=true order by bb.score)) AS arrayConcat 
    

    【讨论】:

    • 是的,我想要这样的东西。但恐怕 cosmosDb 不可能像你说的那样。
    • 在有人提供他们的 sql 语句之前,请相信自己不能在 cosmosdb 中的一个查询中完成。 :)
    • @Tiny-wa - 你为什么说这是不可能的?我已经做到了。我在我的 cmets 中给出了如何做的提示。
    • @Tiny-wa - 我认为 OP 的问题是没有显示示例输出。不清楚,正如所写的那样,它是四个完全独立的子查询组合在一起。
    • @Tiny-wa,如果你有兴趣,可以通过一个简单的查询来完成,但我把它复杂化了。工作解决方案:SELECT * FROM c WHERE c.Status = 0 OR c.Status = 1 ORDER BY c.Status DESC、c.SomeFlag DESC、c.Score DESC。它需要具有这三个字段的复合索引才能工作。感谢您的帮助。
    【解决方案3】:

    正如我的 cmets 中所述,您可以在 where 子句中组合多个表达式,将它们与 orand 组合。

    我认为这里的困惑在于,在您的问题中,您没有提供示例输出,并且有点不清楚您希望如何执行排序。如果总共有四个查询形成一个联合,则可以完成。如果是四个单独的查询,您希望每个子查询在其中进行排序,那么您不能这样做。

    对于前者:在您的示例中,您可以执行以下操作:

    SELECT c.status, c.someFlag, c.score FROM c
    WHERE (c.status = 1 AND c.someFlag = true)
     OR (c.status = 1 AND c.someFlag = false)
     OR (c.status = 0 AND c.someFlag = true)
     OR (c.status = 0 AND c.someFlag = false)
     ORDER BY c.score DESC
    

    输入数据,包括一个将被过滤掉的文档(带有status = 2的文档):

    [
        {
            "status": 0,
            "someFlag": true,
            "score": 24
        },
        {
            "status": 0,
            "someFlag": false,
            "score": 25
        },
        {
            "status": 1,
            "someFlag": true,
            "score": 26
        },
        {
            "status": 1,
            "someFlag": false,
            "score": 27
        },
        {
            "status": 2,
            "someFlag": false,
            "score": 0
        }
    ]
    

    结果:

    [
        {
            "status": 1,
            "someFlag": false,
            "score": 27
        },
        {
            "status": 1,
            "someFlag": true,
            "score": 26
        },
        {
            "status": 0,
            "someFlag": false,
            "score": 25
        },
        {
            "status": 0,
            "someFlag": true,
            "score": 24
        }
    ]
    

    【讨论】:

    • 您的解决方案将按分数对所有这些结果进行排序,这不是我想要的。但是,你是对的,它可以在没有额外工作的情况下完成,我把它复杂化了。工作解决方案:SELECT * FROM c WHERE c.Status = 0 OR c.Status = 1 ORDER BY c.Status DESC、c.SomeFlag DESC、c.Score DESC。它需要具有这三个字段的复合索引才能工作。感谢您的帮助。
    猜你喜欢
    • 2014-06-30
    • 2015-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-29
    • 2017-05-27
    • 2011-02-20
    • 1970-01-01
    相关资源
    最近更新 更多