看来数据存储区中的实体使用其祖先键作为其位置的一部分,这是否可以依赖?

问题描述

这是我的测试设置,它在gcloud beta emulators datastore start --no-store-on-disk的数据存储区模拟器中运行

使用NodeJS客户端进行以下设置。请注意,出于示例的目的,我对祖先使用简单的种类+名称组合。我知道最佳做法文档不鼓励单调生成自定义名称

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

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个结果。请注意,从查询返回的每个实体之间的路径都是正确的:

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

所以我想确认这确实是正确的行为,而不仅仅是模拟器的人工产物。如果这是应该工作的方式,那么接下来就可以考虑使用unix时间戳做一个时间序列,只要祖先的种类+名称提供了足够的保护以防止碰撞。在这种情况下,只要请求写入的进程未以会导致时间戳冲突的规模进行写入,那么UUID可能就足够了。在此示例中,我们假设每个UUID不再需要1个进程。

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

还是这只是个坏主意?

解决方法

这是实体通过键的整个路径键控的正确行为,即它包括所有祖先键。

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