2016-04-18 6 views
0

Ich verwende DynamoDB als Back-End-Datenbank für meine mobile App, und das Schema usw. sind über Android & iOS identisch. Für einen bestimmten Anwendungsfall muss ich einen Scan durchführen, basierend auf zwei Attributen, die nicht indiziert sind. Für iOS Objective C, verwende ich den folgenden Code:AWS DynamoDB Scan schlägt auf iOS fehl, funktioniert aber unter Android

AWSDynamoDBScanExpression *scanExpression = [AWSDynamoDBScanExpression new]; 
    scanExpression.limit = [NSNumber numberWithInt:maxCount]; 
    scanExpression.filterExpression = @"#l = :location AND event = :event"; 
    scanExpression.expressionAttributeNames = @{@"#l":@"location"}; 
    scanExpression.expressionAttributeValues = @{@":location":location, 
               @":event":EVENT_TASTING}; 

Sowohl der Trassierung und sind Strings. EVENT_TASTING ist eine String-Konstante. Dieser Scan führt immer zu Null-Ergebnissen, obwohl ich bestätigt habe, dass die Ergebnisse für die bereitgestellten Einträge erhalten werden sollten. Ich verwende den folgenden Code in Android Java:

DynamoDBScanExpression scanExpression = new DynamoDBScanExpression(); 
     scanExpression.setLimit(maxCount); 

     scanExpression.addFilterCondition("location", 
       new Condition() 
         .withComparisonOperator(ComparisonOperator.EQ) 
         .withAttributeValueList(new AttributeValue().withS(location))); 
     scanExpression.addFilterCondition("event", 
       new Condition() 
         .withComparisonOperator(ComparisonOperator.EQ) 
         .withAttributeValueList(new AttributeValue().withS(Constants.EVENT_TASTING))); 

Der Scan funktioniert wie erwartet in Android. Was muss sich in iOS ändern, damit es auch dort funktioniert? Ich habe iOS SDK auf 2.3.6 aktualisiert, aber es hat keinen Unterschied gemacht. Dies ist die einzige Scanoperation, die ich in meinem Code durchführe.

Gibt es einen Fehler in meinem ScanExpression für iOS? Gibt es eine Möglichkeit, die Android-Stil-Syntax zu verwenden, um dies auf iOS zu arbeiten?

aktualisieren

ich folgende Änderungen versucht:

AWSDynamoDBScanExpression *scanExpression = [AWSDynamoDBScanExpression new]; 
AWSDynamoDBAttributeValue *locationVal = [AWSDynamoDBAttributeValue new]; 
locationVal.S = location; 
AWSDynamoDBAttributeValue *eventVal = [AWSDynamoDBAttributeValue new]; 
eventVal.S = EVENT_TASTING; 
scanExpression.limit = [NSNumber numberWithInt:maxCount]; 
scanExpression.filterExpression = @"#l = :location AND event = :event"; 
scanExpression.expressionAttributeNames = @{@"#l":@"location"}; 
scanExpression.expressionAttributeValues = @{@":location":locationVal, 
              @":event":eventVal}; 

Aber jetzt habe ich eine Störung erhalte:

The request failed. Error: [Error Domain=com.amazonaws.AWSDynamoDBErrorDomain Code=0 "(null)" UserInfo={message=ExpressionAttributeValues contains invalid value: Supplied AttributeValue is empty, must contain exactly one of the supported datatypes for key :location, __type=com.amazon.coral.validate#ValidationException}] 

Antwort

1

Dank des Hinweises von @YosukeMatsuda konnte ich dies beheben, indem ich Scan wiederholt anrufe, bis LastEvaluatedKey leer ist. Ich poste dies als Antwort, weil Mike's Antwort leider nicht auf das richtige Problem hinweist und irreführend ist.

Hier ist, wie ich den Code in iOS geändert:

// In a different method (for first call): 
AWSDynamoDBScanExpression *scanExpression = // See code in original question 

// In a new method that can be called recursively: 
// DynamoDBObjectMapper scan:class-for-model expression:scanExpression 
// continueWithBlock -> if (task.result): 
AWSDynamoDBPaginatedOutput *paginatedOutput = task.result; 
if (paginatedOutput.items.count != 0) 
// Append the paginatedOutput.items to the cumulative array 
else 
// Replace the cumulative array with paginatedOutput.items 
if (paginatedOutput.lastEvaluatedKey.count == 0) { 
    // Scan is complete - handle results 
} else { 
    // Check if you have sufficient results 
    // In my case I had asked for 25 results but was getting 39 
    // So it doesn't seem to obey the scanExpression.limit value 
    // If more results are needed, continue the scan 
    [scanExpression setExclusiveStartKey:paginatedOutput.lastEvaluatedKey]; 
    // Call this method recursively 
} 

Wenn es eine elegantere Lösung ist würde ich es gerne hören. Aber zumindest funktioniert es jetzt.

0

Es gibt mehrere Unterschiede zwischen dem Android Code du bist Verwenden und die ObjectiveC-Version.

  1. in der Android Version verwenden Sie den älteren Filterzustand API, während in dem ObjectiveC Du zum moderneren Filterausdruck API; dies nicht unbedingt die neuere nicht machen, aber es ist nur etwas
  2. im Fall von ExpressionAttributeValues ​​darauf hin, die Werte für location und event, die Sie AWSDynamoDBAttributeValue * Typ sein, keine Strings sind vorbei in sollte; Wenn Sie diese Änderung vornehmen, wird Ihre Abfrage höchstwahrscheinlich funktionieren.

Ich hoffe, dass dies Ihre Frage beantwortet, aber nicht sicher sein kann, weil man nur sagen „dies in Android funktioniert wie erwartet - wie kann ich es in iOS arbeiten machen“ aber Sie sagen uns nicht, was kaputt ist .

+0

Wie schon erwähnt: "Dieser Scan liefert immer null Ergebnisse, obwohl ich bestätigt habe, dass ich für die bereitgestellten Einträge die Ergebnisse erhalten sollte." Und ja, ich benutze die ältere Filterbedingung, weil Android es unterstützt, aber iOS nicht. – LNI

+0

Sie müssen noch angeben, wie Sie "location" und "event" instanziieren. Aktivieren Sie [die ausführliche Protokollierung] (http://docs.aws.amazon.com/mobile/sdkforios/developerguide/setup.html) und aktualisieren Sie die Frage mit der Anfrage JSON. –

+0

Die Frage wurde mit der Ausgabe der ausführlichen Protokollierungsoption aktualisiert. Sowohl Ereignis als auch Ort sind Strings. Die obige Ausgabe zeigt, dass sie korrekt eingestellt sind. Wenn ich in einer Abfrage mithilfe der DynamoDB-Konsole dieselben Werte für Ereignis und Speicherort verwende, gibt der Scan die Werte erfolgreich zurück. – LNI

Verwandte Themen