如何在 CosmosDb 中使用成对约束制定查询?

问题描述 投票:0回答:1

在容器中,我们存储一些具有以下基类和派生类(简化)的项目:

public abstract class MyItemBase
{
    public Guid Id { get; set; }
    public string PartitionKey { get; set; } = "some-customer-id-room";
    public Guid RevisionsId { get; set; }
    public int Revision { get; set; }
    public DateTime CreatedAt { get; set; }
    public Guid CreatedBy { get; set; }
    public bool IsDeleted { get; set; }
}

public class MyRoom : MyItemBase
{
    public string Name { get; set; }
    public int Capacity { get; set; }
}

监视(在本例中)房间的生命周期,我们为每次更改在 Cosmos 中创建一个新项目。要知道哪些物品属于一生,按什么顺序,一个房间的所有物品共享相同的

RevisionsId
,并且
Revision
会加一。也可以通过切换
IsDeleted
标志来删除房间并恢复它。

这是单间可能的生命线:

var sharedRevisionsId = Guid.NewGuid();
var roomChanges = new List<MyRoom>
{
    new() { Id = Guid.NewGuid(), RevisionsId = sharedRevisionsId, Revision = 1, CreatedAt = new DateTime(2024, 2, 16, 17, 0, 0), CreatedBy = Guid.NewGuid(), IsDeleted = false, Name = "Main Hall", Capacity = 100 },
    new() { Id = Guid.NewGuid(), RevisionsId = sharedRevisionsId, Revision = 2, CreatedAt = new DateTime(2024, 2, 17, 13, 0, 0), CreatedBy = Guid.NewGuid(), IsDeleted = false, Name = "Main Hall", Capacity = 90 },
    new() { Id = Guid.NewGuid(), RevisionsId = sharedRevisionsId, Revision = 3, CreatedAt = new DateTime(2024, 2, 18, 11, 0, 0), CreatedBy = Guid.NewGuid(), IsDeleted = true, Name = "Main Hall", Capacity = 90 },
    new() { Id = Guid.NewGuid(), RevisionsId = sharedRevisionsId, Revision = 4, CreatedAt = new DateTime(2024, 2, 19, 19, 0, 0), CreatedBy = Guid.NewGuid(), IsDeleted = false, Name = "Main Hall", Capacity = 90 },
    new() { Id = Guid.NewGuid(), RevisionsId = sharedRevisionsId, Revision = 5, CreatedAt = new DateTime(2024, 2, 20, 20, 0, 0), CreatedBy = Guid.NewGuid(), IsDeleted = true, Name = "Main Hall", Capacity = 90 },
};

在我们的分区键中,我们有多个这样的房间,有些房间还活着,有些在最高版本中被删除。为了在这种环境中支持取消删除功能,我们必须找到该分区键中所有当前已删除的项目。为此,我提出了以下查询:

SELECT
  root.revisionsId,
  MAX(root.revision) as revision
FROM
  root
WHERE
  root.isDeleted
GROUP BY
  root.revisionsId

此查询将返回生命线中某处将

IsDeleted
标志设置为 true 的所有项目,但这一定不是最高版本,因为它可能已经被恢复。因此,我们发送第二个查询,从第一个查询中取出所有候选者,并要求其最高修订版本,无论删除状态如何:

SELECT
  root.revisionsId,
  MAX(root.revision) as revision
FROM
  root
WHERE
  ARRAY_CONTAINS(@revisionsIds, root.revisionsId)
GROUP BY
  root.revisionsId

通过在客户端使用简单的 LINQ-to-object,我们可以找出哪些项目当前处于删除状态:

var deletedItems = deletedCandidates
    .Join(highestRevisions,
        deleted => deleted.RevisionsId,
        highest => highest.RevisionsId,
        (deleted, highest) => (deleted, highest))
    .Where(pair => pair.deleted.Revision == pair.highest.Revision)
    .Select(pair => pair.highest)
    .ToList();

备注:如果您知道如何直接在 Cosmos 中的一个查询中完成上述查找,我将很高兴听到它。

到目前为止一切看起来都很好,但现在我的问题来了: 已删除项目的列表包含整个对象,但由于使用的查询,它们的属性仅部分填充。唯一有意义的属性是

RevisionsId
Revision
,但在下一步中我至少需要这些对象的 Id 或(甚至更好)它们的整个内容。

此时我们拥有的是一个元素列表,我们从每个元素中知道两件事,它们的

RevisionsId
、最高的
Revision
以及
IsDeleted
true

如何制定针对 Cosmos 的查询,以返回所有两个属性对匹配的所有元素?

一些不是的工作想法是

SELECT
  *
FROM
  root
WHERE
  ARRAY_CONTAINS(
    [{"revisionsId":"abc...", "revision":5}, {"revisionsId":"123...", "revision":13}],
    { root.revisionsId, root.revision }
  )
SELECT
  *
FROM
  root
WHERE
  ARRAY_CONTAINS(
    ["abc...", "123..."],
    root.revisionsId
  )
ORDER BY root.revision desc

那么关于如何搜索多个元素(在本例中为房间),其中每个项目必须单独满足多个约束(在本例中为 RevisionsId 和 Revision),有什么想法吗?这个问题听起来很简单,但我确实无法通过给定的模型找到好的方法。

azure-cosmosdb azure-cosmosdb-sqlapi
1个回答
0
投票

根据此文档,匹配对象的语法如下所示。

ARRAY_CONTAINS([<list_of_object>], <object_to_check>)

你所给予的是

ARRAY_CONTAINS(
    [{"revisionsId":"abc...", "revision":5}, {"revisionsId":"123...", "revision":13}],
    { root.revisionsId, root.revision }
  )

{ root.revisionsId, root.revision }
不是要检查的有效对象。

这就是正确的奉献方式。

ARRAY_CONTAINS(
    [{"revisionsId":"abc...", "revision":5}, {"revisionsId":"123...", "revision":13}],
    { "revisionsId":root.revisionsId, "revision":root.revision }
  )

这是示例数据的输出。

查询

SELECT
  root.revisionsId,
  root.revision
FROM
  root
WHERE
  ARRAY_CONTAINS(
    [{"revisionsId":"e326de52-1a84-42d9-bc01-7613a42dc96f", "revision":1}, {"revisionsId":"e326de52-1a84-42d9-bc01-7613a42dc96f", "revision":2}],
    { "revisionsId":root.revisionsId, "revision":root.revision }
  )

输出:

[
    {
        "revisionsId": "e326de52-1a84-42d9-bc01-7613a42dc96f",
        "revision": 1
    },
    {
        "revisionsId": "e326de52-1a84-42d9-bc01-7613a42dc96f",
        "revision": 2
    }
]
© www.soinside.com 2019 - 2024. All rights reserved.