1

我正在嘗試使用DynamoDB實現用戶註冊和登錄。用戶可以通過三種方式登錄。他們可以使用用戶名,電話號碼或電子郵件ID登錄。 我DynamoDB表中有電話號碼作爲主索引散列,因此我能夠加載正確使用 -加載二級索引的記錄

- (void)loadUser:(Class)userClass withHashKey:(NSString*)hashkey withBlock:(void(^)(id))completionBlock{ 
    [[dynamoDBObjectMapper load:userClass hashKey:hashkey rangeKey:nil] 
    continueWithBlock:^id(BFTask *task) { 
     if (task.error) { 
      NSLog(@"The request failed. Error: [%@]", task.error); 
     } 
     if (task.exception) { 
      NSLog(@"The request failed. Exception: [%@]", task.exception); 
     } 
     if (task.result) { 
      if(completionBlock) 
       completionBlock(task.result); 
     } 
     return nil; 
    }]; 
} 

但我不能用同樣的方法輸入用戶名和電子郵件。我收到以下錯誤,當我嘗試使用用戶名或電子郵件代替 -

2015-04-27 19:01:42.549 Barnc[691:122171] AWSiOSSDKv2 [Verbose] AWSURLResponseSerialization.m line:86 | -[AWSJSONResponseSerializer responseObjectForResponse:originalRequest:currentRequest:data:error:] | Response body: [{"__type":"com.amazon.coral.validate#ValidationException","message":"The provided key element does not match the schema"}] 
2015-04-27 19:01:42.556 Barnc[691:122171] The request failed. Error: [Error Domain=com.amazonaws.AWSDynamoDBErrorDomain Code=0 "The operation couldn’t be completed. (com.amazonaws.AWSDynamoDBErrorDomain error 0.)" UserInfo=0x17b96ed0 {message=The provided key element does not match the schema, __type=com.amazon.coral.validate#ValidationException}] 

下面是桌子的細節 Table Details

,這裏是次要全球指數 - Secondary Indices

(對不起,圖像而不是文字,我不知道如何在這裏正確顯示它。)

是否還有其他需要訪問二級索引?我有興趣使用最後兩個索引來使用用戶名或電子郵件加載用戶。

更新:
我的模型類是不同的散列鍵不同,因爲哈希鍵是一個類的方法。這裏是我的父類是什麼樣子 -

//AmazonUser.h 
#import <Foundation/Foundation.h> 
#import <AWSDynamoDB/AWSDynamoDB.h> 
@class BarncUser; 

@interface AmazonUser : AWSDynamoDBObjectModel <AWSDynamoDBModeling> 

@property (nonatomic, strong) NSString *phone_no; 
@property (nonatomic, strong) NSString *password; 
@property (nonatomic, strong) NSString *c2CallPassword; 
@property (nonatomic, strong) NSString *activated; 
@property (nonatomic, strong) NSMutableArray *catalog_ids; 
@property (nonatomic, strong) NSNumber *defaultOnlineStatus; 
@property (nonatomic, strong) NSNumber *signed_in_counts; 
@property (nonatomic, strong) NSNumber *total_referrals; 
@property (nonatomic, strong) NSString *account_creation_date; 
@property (nonatomic, strong) NSString *email_id; 
@property (nonatomic, strong) NSString *account_owner; 
@property (nonatomic, strong) NSString *username; 
@property (nonatomic, strong) NSString *first_name; 
@property (nonatomic, strong) NSString *chat_enabled; 
@property (nonatomic, strong) NSString *last_name; 
@property (nonatomic, strong) NSString *title; 
@property (nonatomic, strong) NSString *last_date_of_sign_out; 
@property (nonatomic, strong) NSString *date_of_birth; 
@property (nonatomic, strong) NSString *last_date_signed_in; 
@property (nonatomic, strong) NSString *address_line1; 

@property (nonatomic, strong) NSString *gplus_user_id; 
@property (nonatomic, strong) NSString *fb_user_id; 

- (void)createDummy; 
- (void)loadFromUser:(BarncUser*)user; 
- (void)loadToUser:(BarncUser*)user; 
@end 

//AmazonUser.m 
@implementation AmazonUser 
+ (NSString *)dynamoDBTableName { 
    return @"Users"; 
} 
+ (NSString *)hashKeyAttribute { 
    return @"phone_no"; 
} 
//implementation of the methods which is not included here. 
@end 

這就是我如何使用了不同的類phone_no和EMAIL_ID哈希鍵 -

//AWSUserWithPhone.m 
#import "AWSUserWithPhone.h" 

@implementation AWSUserWithPhone 

+ (NSString *)hashKeyAttribute { 
    return @"phone_no"; 
} 

@end 


//AWSUserWIthEmail 
#import "AWSUserWithEmail.h" 

@implementation AWSUserWithEmail 

+ (NSString *)hashKeyAttribute { 
    return @"email_id"; 
} 

@end 

在Load方法我只是通過不同用戶的不同類(我用實際方法更新了它)。當我使用phone_no hashkey,一切正常,我得到下面的輸出 -

2015-04-28 13:26:58.908 Barnc[1359:264405] AWSiOSSDKv2 [Verbose] AWSURLRequestSerialization.m line:111 | -[AWSJSONRequestSerializer serializeRequest:headers:parameters:] | Request body: [{"IdentityId":"us-east-1:xxx"}] 
2015-04-28 13:27:01.590 Barnc[1359:264405] AWSiOSSDKv2 [Debug] AWSURLResponseSerialization.m line:81 | -[AWSJSONResponseSerializer responseObjectForResponse:originalRequest:currentRequest:data:error:] | Response header: [{ 
    "Content-Length" = 1052; 
    "Content-Type" = "application/x-amz-json-1.1"; 
    Date = "Tue, 28 Apr 2015 07:57:01 GMT"; 
    "x-amzn-RequestId" = "xxx"; 
}] 
2015-04-28 13:27:01.591 Barnc[1359:264405] AWSiOSSDKv2 [Verbose] AWSURLResponseSerialization.m line:86 | -[AWSJSONResponseSerializer responseObjectForResponse:originalRequest:currentRequest:data:error:] | Response body: [{"Credentials":{"AccessKeyId":"xxx","Expiration":1.430211421E9,"SecretKey":"xxx"},"IdentityId":"us-east-1:xxx"}] 
2015-04-28 13:27:01.648 Barnc[1359:264405] AWSiOSSDKv2 [Verbose] AWSURLRequestSerialization.m line:111 | -[AWSJSONRequestSerializer serializeRequest:headers:parameters:] | Request body: [{"Key":{"phone_no":{"S":"+912222"}},"TableName":"Users"}] 
2015-04-28 13:27:01.661 Barnc[1359:264405] AWSiOSSDKv2 [Debug] AWSSignature.m line:305 | -[AWSSignatureV4Signer signRequestV4:] | AWS4 Canonical Request: [POST 
/

accept-encoding: 
content-type:application/x-amz-json-1.0 
host:dynamodb.us-east-1.amazonaws.com 
user-agent:aws-sdk-iOS/2.1.0 iPhone-OS/8.3 en_IN 
x-amz-date:20150428T075701Z 
x-amz-security-token:xxx 
x-amz-target:DynamoDB_20120810.GetItem 

accept-encoding;content-type;host;user-agent;x-amz-date;x-amz-security-token;x-amz-target 
xxx] 
2015-04-28 13:27:01.663 Barnc[1359:264405] AWSiOSSDKv2 [Debug] AWSSignature.m line:306 | -[AWSSignatureV4Signer signRequestV4:] | payload {"Key":{"phone_no":{"S":"+912222"}},"TableName":"Users"} 
2015-04-28 13:27:01.665 Barnc[1359:264405] AWSiOSSDKv2 [Debug] AWSSignature.m line:322 | -[AWSSignatureV4Signer signRequestV4:] | AWS4 String to Sign: [AWS4-HMAC-SHA256 
20150428T075701Z 
20150428/us-east-1/dynamodb/aws4_request 
xxx] 
2015-04-28 13:27:03.738 Barnc[1359:264405] AWSiOSSDKv2 [Debug] AWSURLResponseSerialization.m line:81 | -[AWSJSONResponseSerializer responseObjectForResponse:originalRequest:currentRequest:data:error:] | Response header: [{ 
    "Content-Length" = 593; 
    "Content-Type" = "application/x-amz-json-1.0"; 
    Date = "Tue, 28 Apr 2015 07:57:03 GMT"; 
    "x-amz-crc32" = 2404923750; 
    "x-amzn-RequestId" = xxx; 
}] 
2015-04-28 13:27:03.739 Barnc[1359:264405] AWSiOSSDKv2 [Verbose] AWSURLResponseSerialization.m line:86 | -[AWSJSONResponseSerializer responseObjectForResponse:originalRequest:currentRequest:data:error:] | Response body: [{"Item":{"fb_user_id":{"S":"null"},"catalog_ids":{"L":[{"S":"0"},{"S":"1"}]},"first_name":{"S":"xxx"},"email_id":{"S":"xxx"},"password":{"S":"xxx"},"date_of_birth":{"S":"xxx"},"phone_no":{"S":"+912222"},"chat_enabled":{"S":"Yes"},"account_creation_date":{"S":"25-Apr-2015"},"title":{"S":"mr"},"last_name":{"S":"xxx"},"account_owner":{"S":"null"},"address_line1":{"S":"null"},"last_date_signed_in":{"S":"25-Apr-2015"},"last_date_of_sign_out":{"S":"25-Apr-2015"},"gplus_user_id":{"S":"null"},"activated":{"S":"Yes"},"c2CallPassword":{"S":"xxx"}}}] 
2015-04-28 13:27:03.768 Barnc[1359:264405] logged 
2015-04-28 13:27:03.771 Barnc[1359:264405] This is a block 
2015-04-28 13:27:05.797 Barnc[1359:263979] observeValueForKeyPath : sessionId 
2015-04-28 13:27:06.189 Barnc[1359:264534] observeValueForKeyPath : ownNumberVerified 
2015-04-28 13:27:06.190 Barnc[1359:264534] ownNumberVerified : 0 
AudioUnitGraph 0x54F000: 
    Member Nodes: 
    node 1: 'auou' 'rioc' 'appl', instance 0x171dab00 O 
    node 2: 'aumx' 'mcmx' 'appl', instance 0x15fea630 O 
    node 3: 'aufc' 'conv' 'appl', instance 0x171b23e0 O 
    Connections: 
    node 2 bus 0 => node 1 bus 0 [ 1 ch, 48000 Hz, 'lpcm' (0x0000000C) 16-bit little-endian signed integer] 
    node 3 bus 0 => node 2 bus 0 [ 1 ch, 48000 Hz, 'lpcm' (0x0000000C) 16-bit little-endian signed integer] 
    Input Callbacks: 
    {0x18d755, 0x172bbf80} => node 2 bus 1 [1 ch, 48000 Hz] 
    {0x18d755, 0x172bbf80} => node 3 bus 0 [1 ch, 8000 Hz] 
    CurrentState: 
    mLastUpdateError=0, eventsToProcess=F, isInitialized=F, isRunning=F 

但是當我使用EMAIL_ID散列鍵,它不工作,並返回ValidationException。下面是完整的詳細日誌 -

2015-04-28 13:31:11.432 Barnc[1359:263979] AWSiOSSDKv2 [Verbose] AWSURLRequestSerialization.m line:111 | -[AWSJSONRequestSerializer serializeRequest:headers:parameters:] | Request body: [{"Key":{"email_id":{"S":"xxx"}},"TableName":"Users"}] 
2015-04-28 13:31:11.443 Barnc[1359:263979] AWSiOSSDKv2 [Debug] AWSSignature.m line:305 | -[AWSSignatureV4Signer signRequestV4:] | AWS4 Canonical Request: [POST 
/

accept-encoding: 
content-type:application/x-amz-json-1.0 
host:dynamodb.us-east-1.amazonaws.com 
user-agent:aws-sdk-iOS/2.1.0 iPhone-OS/8.3 en_IN 
x-amz-date:20150428T080111Z 
x-amz-security-token:xxx 
x-amz-target:DynamoDB_20120810.GetItem 

accept-encoding;content-type;host;user-agent;x-amz-date;x-amz-security-token;x-amz-target 
830520dc23c906e3612ed64618172cd60661698f151658092eb879bcda635827] 
2015-04-28 13:31:11.445 Barnc[1359:263979] AWSiOSSDKv2 [Debug] AWSSignature.m line:306 | -[AWSSignatureV4Signer signRequestV4:] | payload {"Key":{"email_id":{"S":"xxx"}},"TableName":"Users"} 
2015-04-28 13:31:11.446 Barnc[1359:263979] AWSiOSSDKv2 [Debug] AWSSignature.m line:322 | -[AWSSignatureV4Signer signRequestV4:] | AWS4 String to Sign: [AWS4-HMAC-SHA256 
20150428T080111Z 
20150428/us-east-1/dynamodb/aws4_request 
xxx] 
2015-04-28 13:31:11.453 Barnc[1359:265181] plugin com.swiftkey.SwiftKeyApp.Keyboard invalidated 
2015-04-28 13:31:13.291 Barnc[1359:265197] AWSiOSSDKv2 [Debug] AWSURLResponseSerialization.m line:81 | -[AWSJSONResponseSerializer responseObjectForResponse:originalRequest:currentRequest:data:error:] | Response header: [{ 
    "Content-Length" = 121; 
    "Content-Type" = "application/x-amz-json-1.0"; 
    Date = "Tue, 28 Apr 2015 08:01:12 GMT"; 
    "x-amz-crc32" = 3485231410; 
    "x-amzn-RequestId" = xxx; 
}] 
2015-04-28 13:31:13.292 Barnc[1359:265197] AWSiOSSDKv2 [Verbose] AWSURLResponseSerialization.m line:86 | -[AWSJSONResponseSerializer responseObjectForResponse:originalRequest:currentRequest:data:error:] | Response body: [{"__type":"com.amazon.coral.validate#ValidationException","message":"The provided key element does not match the schema"}] 
2015-04-28 13:31:13.301 Barnc[1359:265197] The request failed. Error: [Error Domain=com.amazonaws.AWSDynamoDBErrorDomain Code=0 "The operation couldn’t be completed. (com.amazonaws.AWSDynamoDBErrorDomain error 0.)" UserInfo=0x1727b680 {message=The provided key element does not match the schema, __type=com.amazon.coral.validate#ValidationException}] 

PS:一些信息隱藏的(由xxx和隨機電話號碼標記)出於安全原因。

+0

我不熟悉iOS映射器,但我猜它與Java SDK非常相似,但是可以顯示您的'AWSUserWithPhone'類嗎? – mkobit

+0

@MikeKobit我在問題中增加了更多細節,你現在可以看看嗎? – noob

回答

1

感謝您提供有關您的架構的詳細信息。

此錯誤消息表示您爲表(或索引屬性)定義的鍵之一在請求中沒有正確的AttributeValue類型。請啓用logging並查看您是否可以提供正在創建的實際Put/Update/BatchWrite Item請求的JSON。

此外,您的DynamoDBMapper註釋還可能與您的表的基表和GSI模式不完全對齊。請在此確認或張貼您註釋課程的重要細節。

+0

謝謝你的答案亞歷克斯。我已經用更多的細節更新了我的問題,你能看看嗎? – noob

+0

根據你的線索,你調用GetItem並得到一個驗證異常。 GetItem僅適用於基礎表格,不適用於GSI。您可以使用[Query](http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html)調用來從索引中獲取所需的信息。設置'KeyConditionExpression =「#emailIdPath =:email」','ExpressionAttributeNames = {「#emailIdPath」:「email_id」}','ExpressionAttributeValues = {「:email」:「[email protected]」}','TableName = users'和'IndexName = email_id-index',然後嘗試查詢。 –

+0

謝謝,那是我肯定的問題。我現在使用查詢而不是加載。我相信這對保存操作也是如此。 – noob

0

真正的問題是亞歷山大提到的。我將這個答案發布在iOS代碼的上下文中。 Global Secondary Index不能使用load操作。我們需要query。這裏是我當前的代碼如何加載用戶通過電子郵件看起來象 -

- (void)loadUserWithQuery:(Class)userClass withHashKey:(NSString*)hashkey withIndexName:(NSString*)indexName withBlock:(void(^)(id))completionBlock{ 
    AWSDynamoDBQueryExpression* expression = [AWSDynamoDBQueryExpression new]; 
    expression.hashKeyValues = hashkey; 
    expression.indexName = indexName; 
    expression.scanIndexForward = @YES; 
    expression.limit = @1; 

    [[dynamoDBObjectMapper query:userClass expression:expression] continueWithBlock:^id(BFTask *task) { 
     if (task.error) { 
      NSLog(@"The request failed. Error: [%@]", task.error); 
     } 
     if (task.exception) { 
      NSLog(@"The request failed. Exception: [%@]", task.exception); 
     } 
     if (task.result) { 
      if(completionBlock) 
       completionBlock(task.result); 
     } 
     return nil; 
    }]; 
} 

結果進來AWSDynamoDBPaginatedOutput,所以你需要從那裏提取你的結果。我使用以下代碼 -

AWSDynamoDBPaginatedOutput *output = (AWSDynamoDBPaginatedOutput*)result; 
AmazonUser* user = (AmazonUser*)[output.items objectAtIndex:0]; 

您可以通過添加檢查來查看輸出是否至少有一個項目,以進一步增強它。