首页 > 解决方案 > 似乎数据存储中的实体使用其祖先键作为其位置的一部分,这可以依赖吗?

问题描述

这是我在 Datastore 模拟器中运行的测试设置gcloud beta emulators datastore start --no-store-on-disk

使用 NodeJS 客户端,设置如下。请注意,出于示例的目的,我使用简单的Kind + Name组合作为祖先。我知道最佳实践文档不鼓励单调生成的自定义名称。

const namespace = 'test';
const datastore = new Datastore();
const entities: any[] = [];
const paths = [
    ['A', '1', 'Z', '1'],
    ['A', '2', 'Z', '1'],
    ['A', '3', 'Z', '1'],
    ['A', '4', 'Z', '1'],
];

for (const path of paths) {
    const key = datastore.key({ path, namespace });
    const data = {
      text: 'Lorem Ipsum',
      path: key.path.toString(),
    };

    entities.push({ key, data });
}

const transaction = datastore.transaction();
await transaction.run();

transaction.upsert(entities);
await transaction.commit();

// wait a second for things to persist.
await new Promise((resolve) => {
    setTimeout(() => resolve(), 1000);
});

// Note that `hasAncestor` is **NOT** provided for this query.
const query = datastore.createQuery(namespace, 'Z');

const results = await datastore.runQuery(query);
expect(results[0]).toHaveLength(1); // fails, got 4 records back

Z如果祖先路径与实体查找位置无关,我希望在查询所有种类的实体时只有 1 个结果。但在我的测试中并非如此,我得到了 4 个结果。请注意,从查询返回的每个实体之间的路径是正确的:

[
    {
        "path": "A,1,Z,1",
        "text": "Lorem Ipsum"
    },
    {
        "path": "A,2,Z,1",
        "text": "Lorem Ipsum"
    },
    {
        "path": "A,3,Z,1",
        "text": "Lorem Ipsum"
    },
    {
        "path": "A,4,Z,1",
        "text": "Lorem Ipsum"
    }
]

所以我想确认这确实是正确的行为,而不仅仅是模拟器的工件。如果事情应该是这样工作的,那么只要祖先的Kind + Name提供足够的碰撞保护,就可以使用 unix 时间戳来查看时间序列。在这种情况下,只要请求写入的进程没有以会导致时间戳冲突的规模写入,UUID 可能就足够了。在这个例子中,我们假设每个 UUID 有 1 个进程,不再有。

['A', '95a69d2f-adac-4da7-b1ab-134ca0e7a840', 'Z', '1000000005000']
['A', '95a69d2f-adac-4da7-b1ab-134ca0e7a840', 'Z', '1000000006000']
['A', '95a69d2f-adac-4da7-b1ab-134ca0e7a840', 'Z', '1000000007000']

或者这仍然只是一个坏主意?

标签: google-cloud-firestoregoogle-cloud-datastore

解决方案


这是一个实体由整个密钥路径作为密钥的正确行为,即它包括所有祖先密钥。

如果您有一个唯一的(每个进程)前缀,那么您不必担心单调递增的键,因为写入实际上是由您的前缀在键空间中隔开的。因此,这应该是一个可扩展的解决方案。


推荐阅读