web-dev-qa-db-fra.com

AWS DynamoDB Scan et FilterExpression utilisant un tableau de valeurs de hachage

J'ai de la difficulté à trouver un exemple utile d'analyse avec FilterExpression sur une table DynamoDB. J'utilise le SDK javascript dans le navigateur. 

Je souhaite analyser ma table et renvoyer uniquement les enregistrements ayant des valeurs "UID" de champ HASH dans un tableau que je transmets à l'analyse.

Disons que j'ai un tableau d'identifiants uniques qui constituent le champ de hachage de ma table J'aimerais interroger ces enregistrements à partir de ma table DynamoDB. 

Quelque chose comme ci-dessous 

var idsToSearch=['123','456','789'] //array of the HASH values I would like to retrieve
var tableToSearch = new AWS.DynamoDB();
var scanParams = {
  "TableName":"myAwsTable",  
  "AttributesToGet":['ID','COMMENTS','DATE'],  
  "FilterExpression":"'ID' in "+idsToSearch+"" 

}
tableToSearch.scan(scanParams), function(err,data){
    if (err) console.log(err, err.stack); //error handler
    else console.log(data); //success response
})
14
jotamon

Vous devriez utiliser l'opérateur IN. Il est également plus facile d’utiliser Placeholders pour les noms d’attributs et les valeurs d’attributs. Je vous conseillerais toutefois de ne pas utiliser Scan dans ce cas. Il semble que vous ayez déjà les valeurs d'attribut de clé de hachage que vous souhaitez rechercher. Il serait donc plus logique d'utiliser BatchGetItem .

Quoi qu'il en soit, voici comment procéder en Java:

ScanSpec scanSpec = new ScanSpec()
    .withFilterExpression("#idname in (:val1, :val2, :val3)")
    .withNameMap(ImmutableMap.of("#idname", "ID"))
    .withValueMap(ImmutableMap.of(":val1", "123", ":val2", "456", ":val23", "789"));
ItemCollection<ScanOutcome> = table.scan(scanSpec);

J'imagine que, avec le SDK Javascript, cela ressemble à ceci:

var scanParams = {
  "TableName":"myAwsTable",
  "AttributesToGet": ['ID','COMMENTS','DATE'],
  "FilterExpression": '#idname in (:val1, :val2, :val3)',
  "ExpressionAttributeNames": {
    '#idname': 'ID'
  },
  "ExpressionAttributeValues": {
    ':val1': '123',
    ':val2': '456',
    ':val3': '789'
  }
}
12
mkobit

J'ai eu ce problème et l'a trouvé en utilisant contient paramètre

// Object stored in the DB looks like this: 
// [
//     'name' => 'myName',
//     'age' => '24',
//     'gender' => 'Male',
//     'visited' => [
//          'countries': ['Canada', 'USA', 'Japan', 'Australia'],
//          'last_trip': '2015/12/13',
//          'reviews_written': 20
//     ]
// 
// ];

$countries = ['Canada', 'USA', 'Japan', 'Australia'];

$paramToMatch = '24';

$client->query([
        'TableName'     => 'MyDyanmoDB',
        'KeyConditions' => [
            'age' => [
                'AttributeValueList' => [
                    $marshaler->marshalValue($paramToMatch)
                ],
                'ComparisonOperator' => 'EQ'
            ]
        ],
        'ExpressionAttributeNames' => [
            '#visited'   => 'visited',
            '#countries' => 'countries'
        ],
        'ExpressionAttributeValues' => [
            ':countries' => $marshaler->marshalValue($countries)
        ],
        'FilterExpression' => 'contains(:countries, #visited.#countries)',
]);
7
tsuz

Voici comment j'ai pu utiliser "scan" pour obtenir les éléments avec un identifiant particulier ("ContentID") dans l'exemple ci-dessous:

var params = {
    TableName: environment.ddbContentTableName,
    ProjectionExpression: "Title, ContentId, Link",
    FilterExpression: "ContentId in (:contentId1, :contentId2, :contentId3, :contentId4),
    ExpressionAttributeValues: {":contentId1":102,":contentId2":104,":contentId3":103,":contentId4":101}
};

var docClient = new AWS.DynamoDB.DocumentClient();
docClient.scan(params, onQuery); 

Je peux ensuite construire par programmation les valeurs FilterExpression et ExpressionAttributeValues ​​en fonction de valeurs connues, par exemple.

    // Create the FilterExpression and ExpressionAttributeValues
    var filterExpression =  "ContentId in ("; 

    var expressionAttributeValues = {};

    for (var i = 0; i < currentFavorites.length; i++) { 
        var contentIdName = ":contentId"+(i+1);

        if (i==0) {
            filterExpression = filterExpression + contentIdName;
        } else {
            filterExpression = filterExpression + ", " + contentIdName;
        }

        expressionAttributeValues[contentIdName] = currentFavorites[i];
    }

    filterExpression = filterExpression + ")";

    var params = {
        TableName: environment.ddbContentTableName,
        ProjectionExpression: "Title, ContentId, Link",
        FilterExpression: filterExpression,
        ExpressionAttributeValues: expressionAttributeValues
    };

    var docClient = new AWS.DynamoDB.DocumentClient();
    docClient.scan(params, onQuery); 
2
xke

Je recherchais également une solution dynamique, plutôt que de devoir mettre manuellement chacun des noms de paramètres dans l'expression conditionnelle. Voici une solution: 

List<String> valList= new ArrayList<String>(); // Populate the Values in a List    
StringJoiner valMap =  new StringJoiner(","); // This will be the dynamic Value Map

int i=1;

        table = dynamoDB.getTable(myTable);
        StringBuilder filterExpression = new StringBuilder();
        Map<String, Object> eav = new HashMap<String, Object>();

        if(!valList.isEmpty())
        {
            for(String attrVal: valList)
             {
                eav.put(":val"+i, attrVal);
                valMap.add(":val"+i);
                i++;
            }   
            filterExpression.append("attrColName in ("+valMap.toString()+")"); //here attrColName is the DB attribute
        }

        ItemCollection<ScanOutcome> items;
            items = table.scan(
                filterExpression.toString(), //FilterExpression
                null, //ProjectionExpression - choose all columns
                null, //ExpressionAttributeNames - not used in this example
                eav);//ExpressionAttributeValues 
0
javatogo