Как фильтровать по элементам в массиве (или вложенном объекте) в DynamoDB - PullRequest
0 голосов
/ 30 апреля 2018

Мои данные следующие:

[
  {
    orgId: "ABC",
    categories: [
      "music",
      "dance"
    ]
  },
  {
    orgId: "XYZ",
    categories: [
      "math",
      "science",
      "art"
    ]
  },
  ...
]

У меня есть первичный ключ на orgId, и я хочу использовать DynamoDB query, чтобы фильтровать и возвращать только элементы с категорией "наука", например.

(Категория не должна быть частью какого-либо индекса: я готов принять дополнительные накладные расходы при условии, что я могу выполнить запрос в самом Dynamo.)

У меня есть время, чтобы заставить это работать. Я могу легко изменить categories на вложенные объекты, если это поможет?

Но операторы сравнения настолько ограничены в DynamoDB, что кажется, что нет способа фильтровать элементы массива или вложенные объекты?

Если нет, то какой подход лучше? Чтобы превратить каждую категорию в свой собственный атрибут первого уровня, например:

[
  {
    orgId: "XYZ",
    category_math: true,
    category_science: true
  }
]

Конечно, нет?

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

Ответ, опубликованный выше, должен работать согласно документации. Но при использовании Node.JS AWS DynamoDB SDK DocumentClient это не так. В частности, я попробовал:

  {
    TableName: "site",
    IndexName: "orgId-lastCaptured-index",
    KeyConditionExpression: "orgId = :orgId",
    FilterExpression: "categories CONTAINS :categoriesValue",
    ExpressionAttributeValues: {
      ":orgId": orgId,
      ":categoriesValue": myVariable,
    }
  }

Это привело к следующей ошибке: { ValidationException: Invalid FilterExpression: Syntax error; token: "CONTAINS", near: "categories CONTAINS :categoriesValue"

Я настроил запрос на альтернативное форматирование запроса следующим образом:

  {
    TableName: "site",
    IndexName: "orgId-lastCaptured-index",
    KeyConditions: {
      orgId: {
        ComparisonOperator: "EQ",
        AttributeValueList: [orgId],
      },
    },
    QueryFilter: {
      categories: {
        ComparisonOperator: "CONTAINS",
        AttributeValueList: [myVariable],
      }
    }
  }

Это сработало, как и ожидалось, отфильтровав возвращаемые результаты так, что переменная categories имеет элемент, соответствующий myVariable.

Обновление: теперь вы можете выполнять CONTAINS операций без использования устаревшего QueryFilter с этим синтаксисом: FilterExpression: "contains(categories, :categoriesValue)"

0 голосов
/ 30 апреля 2018
 var params = {
  ExpressionAttributeValues: {
   ":orgIdValue": {
     S: "XYZ"
    },
   ":categoriesValue": {
     S: "science"
    }
  }, 
  KeyConditionExpression: "orgId = :orgIdValue", 
  FilterExpression : "categories CONTAINS :categoriesValue", 
  TableName: "MYTABLE"
 };
 dynamodb.query(params, function(err, data) {
   if (err) console.log(err, err.stack); // an error occurred
   else     console.log(data);           // successful response
 });

CONTAINS: проверяет подпоследовательность или значение в наборе. AttributeValueList может содержать только один элемент AttributeValue типа String, Number или Binary (не заданного типа). Если целевой атрибут сравнение имеет тип String, затем оператор проверяет наличие совпадение подстроки. Если целевой атрибут сравнения имеет тип Двоичный, то оператор ищет подпоследовательность цели, которая соответствует входу. Если целевой атрибут сравнения является набором ("SS", "NS" или "BS"), тогда оператор оценивает значение true, если находит точное совпадение с любым членом набора. CONTAINS поддерживается для списки: при оценке «a CONTAINS b» «a» может быть списком ; однако "б" не может быть набором, картой или списком.

Категории - это атрибут верхнего уровня, у вас нет вложенных атрибутов. Скалярные атрибуты верхнего уровня могут быть проиндексированы. Хотя категории верхнего уровня, это не скалярный атрибут (это набор), поэтому вы не можете его проиндексировать.

Вы можете использовать FilterExpression, чтобы сузить ваш запрос, и вы можете использовать компаратор CONTAINS в списках.

...