12

I have one field which i have declared as string in the model as show below:

App.Student= DS.Model.extend({
name: DS.attr('string'),
address1: DS.attr('string'),
address2: DS.attr('string'),
city: DS.attr('string'),
state: DS.attr('string'),
postal: DS.attr('string'),
country: DS.attr('string'),
});

Here in the Edit mode when i update Adderess 2 field as null then below error comes:

"Failed to edit property: One or more parameter values were invalid: An AttributeValue may not contain an empty string"

I know this Error is generated because i am updating address 2 field as null and that what i want Address 2 field is not mandatory(One can pass data or can also left that column as blank")

Trilok Pathak
  • 2,931
  • 4
  • 28
  • 34

7 Answers7

5

If you are using DynamoDB (not DocumentClient) you can specify nulls like this

const putItem: PutItemInput = {
  TableName: `${process.env.PRIMARY_TABLE}`,
  Item: {
    key: { S: ${userId}` },
    someField: { NULL: true }
  }
}
Zayin Krige
  • 3,229
  • 1
  • 35
  • 34
4

Finally i got this right, The way might be some what different but it work for me !!!

Here is the code for the same.

AttributeUpdates: {
                     Address2: 
                     {
                        Action: "DELETE"
                     },
                  }

And then i am adding the value on the condition.

if (propertyObj.address2) {
        params.AttributeUpdates.address2 = {
            Value: {
                S: propertyObj.address2
            },
            Action: "PUT"
        }
    }

Thank you to all from bottom of my heart :)who tried to help me, Cheers !!!

Trilok Pathak
  • 2,931
  • 4
  • 28
  • 34
  • 1
    FYI, DynamoDb now supports empty string values for non-key attributes: https://aws.amazon.com/about-aws/whats-new/2020/05/amazon-dynamodb-now-supports-empty-values-for-non-key-string-and-binary-attributes-in-dynamodb-tables/ – Elroy Flynn May 19 '20 at 19:05
  • Also FYI you [*don't need to map the attribute itself at all*](https://stackoverflow.com/a/62723116/1357094), in order to represent "no value". – cellepo Jul 03 '20 at 22:01
4

I just pass nulls. Here's my NodeJS script for loading data from file into DynamoDB, I just use ternaries to avoid empty strings.

var AWS = require("aws-sdk");
var fs = require('fs');

// Make sure we got a filename on the command line.
if (process.argv.length < 3) {
  console.log('Usage: node ' + process.argv[1] + ' FILENAME');
  process.exit(1);
}

var filename = process.argv[2];

AWS.config.update({
    region: "us-west-2",
    //endpoint: "http://localhost:8000"
});

var docClient = new AWS.DynamoDB.DocumentClient();

console.log("Importing Addresses into DynamoDB. Please wait.");

var allObjs = JSON.parse(fs.readFileSync(filename, 'utf8'));
allObjs.forEach(function(obj) {
    var params = {
        TableName: "Address",
        Item: {
            "address_detail_pid":  obj.address_detail_pid,
            "flat_type":  obj.flat_type == '' ? null : obj.flat_type,
            "flat_number":  obj.flat_number == '' ? null : obj.flat_number,
            "level_type":  obj.level_type == '' ? null : obj.level_type,
            "level_number":  obj.level_number == '' ? null : obj.level_number,
            "number_first":  obj.number_first == '' ? null : obj.number_first,
            "street_name":  obj.street_name == '' ? null : obj.street_name,
            "street_type_code":  obj.street_type_code == '' ? null : obj.street_type_code,
            "locality_name":  obj.locality_name == '' ? null : obj.locality_name,
            "state_abbreviation":  obj.state_abbreviation == '' ? null : obj.state_abbreviation,
            "postcode":  obj.postcode == '' ? null : obj.postcode,
            "longitude":  obj.longitude == '' ? null : obj.longitude,
            "latitude":  obj.latitude == '' ? null : obj.latitude
        }
    };

    docClient.put(params, function(err, data) {
       if (err) {
           console.error("Unable to add obj", obj.address_detail_pid, ". Error JSON:", JSON.stringify(err, null, 2));
       } else {
           console.log("PutItem succeeded:", obj.address_detail_pid);
       }
    });
});
user326608
  • 2,210
  • 1
  • 26
  • 33
  • 1
    Your answer should be the de facto solution for handling empty strings/values. My understanding, however, is that this is permissible for `DocumentClient.put` and not `PutItem`. For others, see http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html – user1322092 Dec 30 '16 at 17:27
  • One caveat, I wasn't able to query against a GSI that includes the field set to null as a range value. – user1322092 Dec 31 '16 at 22:44
4

I think the best way is to check if the value of the field is blank and not save the value in the database.

When the field is blank, we should not include it in the attribute value map.

Here is the code snippet I have used in GO language

myAttributeValues := map[string]*dynamodb.AttributeValue{
        “field1”: {
            S: aws.String(value1),
        },
        “field2”: {
            S: aws.String(value2),
        },
        “field3”: {
            S: aws.String(value3),
        },      
    }

    if field4  != "" {
        field4Attribute := dynamodb.AttributeValue{
            S: aws.String(value4),
        }
        myAttributeValues[“field4”] = &field4Attribute
    }

    if field5 != "" {
        field5Attribute := dynamodb.AttributeValue{
            S: aws.String(value5),
        }
        myAttributeValues["field5"] = &field5Attribute
    }

    input := &dynamodb.PutItemInput{

        TableName: aws.String(mytableName),
        Item:      myAttributeValues,
    }
Dattatray
  • 1,745
  • 1
  • 21
  • 49
2

You can use AttributeValue null type as a placeholder. If you cannot change the type, then, choose a sentinel value, like "ZZZZZ" or similar and make that represent the empty string. Alternatively, your model could just have one address field, and then, you could encode both address lines in address1, if the second address line is null/empty.

Alexander Patrikalakis
  • 5,054
  • 1
  • 30
  • 48
  • It is already declares as a string and i also can not make it to "Attributes value Null" is there any other way to do the same where datatype remains the same as "String" and i can do the operation ? – Trilok Pathak Jul 06 '15 at 07:23
2

AWS finally resolved this issue. DynamoDb now supports empty string values for non-key attributes: https://aws.amazon.com/about-aws/whats-new/2020/05/amazon-dynamodb-now-supports-empty-values-for-non-key-string-and-binary-attributes-in-dynamodb-tables/

kev
  • 79
  • 1
  • 1
2

Since DynamoDB is NoSQL, you can look at this in an entirely different way:

Instead of trying to add a "null"/empty value into DynamoDB, just plan on not attempting to add the attribute itself with the "null" value in the first place...

"null"-check in code, instead by checking if the attribute itself is present [by attribute name]:

  • If not present, interpret that as "null" for the state of that variable/attribute in code
  • If present, then it has a non-null value
  • If trying to set an existing attribute from non-"null" to "null", just remove the attribute
  • If trying to set what is ("conceptually" at the moment) a "null" value to non-"null", add the attribute [with its non-"null" value]

Note my use of quotes on "null" above - I did that on purpose to emphasize that if you use this thinking of representing null by not mapping its attribute itself, then there is no attribute that actually exists as "null" (no attribute that actually holds an actual "null" value).

*Besides the benefit of capturing "null"-checking in this way being possible in itself, this strategy has an additional benefit of saving [at least some] DynamoDB storage space, & read/write capacity units (i.e: on-demand pricing limits 1 write unit to 1kb & 1 read unit to 4kb): No attribute stored to represent "null" means no storage otherwise spent! I don't for a fact, but I am guessing Amazon intentionally makes AWS architecture design choices to force decisions/tradeoffs like this: Operate under constraint of things like {no null values, no empty sets}, and save resources that would otherwise be spent on them.

Once again, this is all possible because of DynamoDB's NoSQL implementation - unlike a SQL database, NoSQL data can be unstructured; and in particular, the unstructured-ness can be leveraged in this case to include an attribute in some documents in a given DynamoDB table and not other documents (in the same table). It is impossible to do the analogous same thing in a SQL database as each db row there must have all columns - that's what forces having to set a SQL variable/column to null for records where "no value" is desired (note my different formatting of null in this sentence ;), and not being able to just "not include the column/variable" on that row. NoSQL's version to "not include a column on some rows" is possible by just not including an attribute (which it can do because NoSQL is unstructured :)

*This strategy can still be used for benefits despite the fact that Amazon DynamoDB now supports empty values for non-key String and Binary attributes - this strategy would still at least have the exceeding benefit of saving space.

*Note this strategy can also be used to represent an "empty set" (since in DynamoDB sets must have at least 1 value) - just don't map the set attribute until it is desired to be non-empty ;)

[This strategy can be read in a similar discussion for MongoDB]

cellepo
  • 4,001
  • 2
  • 38
  • 57
  • 1
    Further to the storage benefits, if you have a GSI that's keyed on that attribute, you can save a huge amount if you omit the attribute. This is because the index will be much smaller. E.g. if your main DDB table has 1 million rows, and you have a GSI on `address2`, which is only filled in for 10,000 rows, then your entire GSI will only have 10,000 rows, as opposed to 1 million if you set it to `"null"`. – stwr667 Aug 09 '23 at 09:19