在数据存储区的嵌入式实体中使用 excludeFromIndexes 的正确方法是什么

What's the right way to use excludeFromIndexes in an Embedded Entity in Datastore

Datastore 不允许超过 1500 字节的属性被索引。所以如果我有一个对象

{foo : X, bar : Y}

如果 Y 超过 1500 个字符,我可以禁用对单个 属性 的索引并通过数组存储它,因此:

[
 { name : 'foo', value: 'X'}, 
 { name: 'bar', value: 'Y', excludeFromIndexes: true}
]

但如果 属性 是嵌入实体的一部分(即另一个实体的 属性 中的实体),则此方法无效。 我该如何存储这样的东西?

{ foo : X, bar : { baz : Y } }

这不起作用:

[
 { name : 'foo', value: 'X'}, 
 { name: 'bar', value: 
    {
        name: 'baz', 
        value: 'Y', 
        excludeFromIndexes: true
    },
 excludeFromIndexes: true}
]

这也是:

[
 { name : 'foo', value: 'X'}, 
 { name: 'bar', value: {'baz', 'Y' }, excludeFromIndexes: true}
]

更新: 这是一个示例片段:

const DataStore = require('@google-cloud/datastore');
const datastore = DataStore({projectId});
const foo1 = { name : { forename: 'Dave', surname : 'Tong' }, colour : 'blue'}

const putAndGet = async data => {
  return new Promise(async (resolve, reject) => {
    try {
      const key = await datastore.save({key: datastore.key([Kind]), data: data});
    } catch (err) {
      reject(err);
    }
    const results = [];
    const query = datastore.createQuery(Kind);
    query.runStream()
      .on('error', (error) => {
        reject(new Error(error));
      })
      .on('data', (entity) => {
        results.push(entity);
      })
      .on('end', () => {
        resolve(results);
      });
  });
}

// This will succeed
putAndGet(foo1).then(ret => {
  for (var i = 0; i < ret.length; i++) {
    console.log(ret[i].name.forename + " likes " + ret[i].colour);
  }

  const str = [];
  for (var i = 0; i < 400; i++) str[i] = 'X';

  const foo2 = {name: {forename: str.join('XXX'), surname: 'Tong'}, colour: 'blue'}
  // This will fail
  return putAndGet(foo2);
}).then(ret => {
  for (var i = 0; i < ret.length; i++) {
    console.log(ret[i].name.forename + " likes " + ret[i].colour);
  }
}).catch(err => {
  console.log(err.message);
});

经过一些测试,我能够实现你想要做的事情。我还编辑了你的问题,为了让这个 post 的未来读者更清楚,因为你指的是“属性 part of another 属性”,但它在 Datastore 中定义为 EmbeddedEntity,因此我将坚持使用该名称以获得更清晰的解释。

嵌入式实体可以具有超过 1500 字节的子属性,但您必须明确排除这些子属性,否则将显示错误。为此,您必须将每个 EmbeddedEntity 声明为:

{
  "properties": {
    "surname": {
      "stringValue": "A long surname which has more than 1500B",
      "excludeFromIndexes": true
    },
    "forename": {
      "stringValue": "David"
    }
  }
}

但是使用 NodeJS 以编程方式声明 "excludeFromIndexes": true 并不是很简单。但是最后我设法解决了它。关键是 save() 函数,您可以在其中声明要从索引中排除的 propertiessubproperties,例如:

datastore.save({key: entity_key, data: entity_data, excludeFromIndexes: ['prop1', 'prop2.subprop1']});

我在这里分享一小段代码(这是您分享的那段代码的 MCV),它可以工作并创建一个实体,其中包含一些包含长超属性的属性:

const DataStore = require('@google-cloud/datastore');

const projectId = "YOUR_PROJECT_ID";
const datastore = DataStore({projectId});

const data = {name: {forename: 'David', surname: '<YOUR_LONG_STRING>'}, colour: 'purple'}

const Kind = "<YOUR_ENTITY_KIND>";

datastore
  .save({key: datastore.key([Kind]), data: data, excludeFromIndexes: ['name.surname']})
  .then(() => {
    console.log(`Entity saved`);
  })
  .catch(err => {
    console.error('ERROR:', err);
  });

一旦你 运行 这段代码,如果你检查你 Datastore dashboard 中的实体,你将能够看到你的 EmbeddedEntity 是我在回答开头分享的定义.