Arbeiten Sie mit Attributen wie Beans, Maps, Listen und Sets - AWS SDK for Java 2.x

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Arbeiten Sie mit Attributen wie Beans, Maps, Listen und Sets

Eine Bean-Definition, wie die unten gezeigte Person Klasse, könnte Eigenschaften (oder Attribute) definieren, die sich auf Typen mit zusätzlichen Attributen beziehen. In der Person Klasse mainAddress handelt es sich beispielsweise um eine Eigenschaft, die sich auf ein Address Bean bezieht, das zusätzliche Wertattribute definiert. addressesbezieht sich auf eine Java-Map, deren Elemente sich auf Address Beans beziehen. Diese komplexen Typen können als Container mit einfachen Attributen betrachtet werden, die Sie für ihren Datenwert im Kontext von DynamoDB verwenden.

DynamoDB bezeichnet die Werteigenschaften verschachtelter Elemente wie Maps, Listen oder Beans als verschachtelte Attribute. Im Amazon DynamoDB Developer Guide wird die gespeicherte Form einer Java-Map, -Liste oder -Bean als Dokumenttyp bezeichnet. Einfache Attribute, die Sie in Java für ihren Datenwert verwenden, werden in DynamoDB als skalare Typen bezeichnet. Mengen, die mehrere skalare Elemente desselben Typs enthalten und als Mengentypen bezeichnet werden.

Es ist wichtig zu wissen, dass der DynamoDB Enhanced Client eine Eigenschaft, die Bean ist, beim Speichern in einen DynamoDB-Kartendokumenttyp API konvertiert.

@DynamoDbBean public class Person { private Integer id; private String firstName; private String lastName; private Integer age; private Address mainAddress; private Map<String, Address> addresses; private List<PhoneNumber> phoneNumbers; private Set<String> hobbies; @DynamoDbPartitionKey public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Address getMainAddress() { return mainAddress; } public void setMainAddress(Address mainAddress) { this.mainAddress = mainAddress; } public Map<String, Address> getAddresses() { return addresses; } public void setAddresses(Map<String, Address> addresses) { this.addresses = addresses; } public List<PhoneNumber> getPhoneNumbers() { return phoneNumbers; } public void setPhoneNumbers(List<PhoneNumber> phoneNumbers) { this.phoneNumbers = phoneNumbers; } public Set<String> getHobbies() { return hobbies; } public void setHobbies(Set<String> hobbies) { this.hobbies = hobbies; } @Override public String toString() { return "Person{" + "addresses=" + addresses + ", id=" + id + ", firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + ", age=" + age + ", mainAddress=" + mainAddress + ", phoneNumbers=" + phoneNumbers + ", hobbies=" + hobbies + '}'; } }
@DynamoDbBean public class Address { private String street; private String city; private String state; private String zipCode; public Address() { } public String getStreet() { return this.street; } public String getCity() { return this.city; } public String getState() { return this.state; } public String getZipCode() { return this.zipCode; } public void setStreet(String street) { this.street = street; } public void setCity(String city) { this.city = city; } public void setState(String state) { this.state = state; } public void setZipCode(String zipCode) { this.zipCode = zipCode; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Address address = (Address) o; return Objects.equals(street, address.street) && Objects.equals(city, address.city) && Objects.equals(state, address.state) && Objects.equals(zipCode, address.zipCode); } @Override public int hashCode() { return Objects.hash(street, city, state, zipCode); } @Override public String toString() { return "Address{" + "street='" + street + '\'' + ", city='" + city + '\'' + ", state='" + state + '\'' + ", zipCode='" + zipCode + '\'' + '}'; } }
@DynamoDbBean public class PhoneNumber { String type; String number; public String getType() { return type; } public void setType(String type) { this.type = type; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } @Override public String toString() { return "PhoneNumber{" + "type='" + type + '\'' + ", number='" + number + '\'' + '}'; } }

Speichern Sie komplexe Typen

Verwenden Sie annotierte Datenklassen

Sie speichern verschachtelte Attribute für benutzerdefinierte Klassen, indem Sie sie einfach mit Anmerkungen versehen. Die Address Klasse und die PhoneNumber Klasse, die zuvor gezeigt wurden, sind nur mit der Anmerkung annotiert. @DynamoDbBean Wenn der DynamoDB Enhanced Client das Tabellenschema für die Person Klasse mit dem folgenden Codeausschnitt API erstellt, API erkennt er die Verwendung der PhoneNumber Klassen Address und und erstellt die entsprechenden Mappings für die Arbeit mit DynamoDB.

TableSchema<Person> personTableSchema = TableSchema.fromBean(Person.class);

Verwenden Sie abstrakte Schemas mit Buildern

Der alternative Ansatz besteht darin, Schema-Builder für statische Tabellen für jede verschachtelte Bean-Klasse zu verwenden, wie im folgenden Code gezeigt.

Die Tabellenschemas für die PhoneNumber Klassen Address und sind abstrakt in dem Sinne, dass sie nicht mit einer DynamoDB-Tabelle verwendet werden können. Das liegt daran, dass ihnen Definitionen für den Primärschlüssel fehlen. Sie werden jedoch als verschachtelte Schemas im Tabellenschema für die Person Klasse verwendet.

Nach den Kommentarzeilen 1 und 2 in der Definition von sehen Sie den CodePERSON_TABLE_SCHEMA, der die abstrakten Tabellenschemas verwendet. Die Verwendung von documentOf in der EnhanceType.documentOf(...) Methode bedeutet nicht, dass die Methode einen EnhancedDocument Typ des erweiterten Dokuments API zurückgibt. Die documentOf(...) Methode gibt in diesem Kontext ein Objekt zurück, das weiß, wie es sein Klassenargument mithilfe des Tabellenschema-Arguments DynamoDB-Tabellenattributen zuordnen kann.

// Abstract table schema that cannot be used to work with a DynamoDB table, // but can be used as a nested schema. public static final TableSchema<Address> TABLE_SCHEMA_ADDRESS = TableSchema.builder(Address.class) .newItemSupplier(Address::new) .addAttribute(String.class, a -> a.name("street") .getter(Address::getStreet) .setter(Address::setStreet)) .addAttribute(String.class, a -> a.name("city") .getter(Address::getCity) .setter(Address::setCity)) .addAttribute(String.class, a -> a.name("zipcode") .getter(Address::getZipCode) .setter(Address::setZipCode)) .addAttribute(String.class, a -> a.name("state") .getter(Address::getState) .setter(Address::setState)) .build(); // Abstract table schema that cannot be used to work with a DynamoDB table, // but can be used as a nested schema. public static final TableSchema<PhoneNumber> TABLE_SCHEMA_PHONENUMBER = TableSchema.builder(PhoneNumber.class) .newItemSupplier(PhoneNumber::new) .addAttribute(String.class, a -> a.name("type") .getter(PhoneNumber::getType) .setter(PhoneNumber::setType)) .addAttribute(String.class, a -> a.name("number") .getter(PhoneNumber::getNumber) .setter(PhoneNumber::setNumber)) .build(); // A static table schema that can be used with a DynamoDB table. // The table schema contains two nested schemas that are used to perform mapping to/from DynamoDB. public static final TableSchema<Person> PERSON_TABLE_SCHEMA = TableSchema.builder(Person.class) .newItemSupplier(Person::new) .addAttribute(Integer.class, a -> a.name("id") .getter(Person::getId) .setter(Person::setId) .addTag(StaticAttributeTags.primaryPartitionKey())) .addAttribute(String.class, a -> a.name("firstName") .getter(Person::getFirstName) .setter(Person::setFirstName)) .addAttribute(String.class, a -> a.name("lastName") .getter(Person::getLastName) .setter(Person::setLastName)) .addAttribute(Integer.class, a -> a.name("age") .getter(Person::getAge) .setter(Person::setAge)) .addAttribute(EnhancedType.documentOf(Address.class, TABLE_SCHEMA_ADDRESS), a -> a.name("mainAddress") .getter(Person::getMainAddress) .setter(Person::setMainAddress)) .addAttribute(EnhancedType.listOf(String.class), a -> a.name("hobbies") .getter(Person::getHobbies) .setter(Person::setHobbies)) .addAttribute(EnhancedType.mapOf( EnhancedType.of(String.class), // 1. Use mapping functionality of the Address table schema. EnhancedType.documentOf(Address.class, TABLE_SCHEMA_ADDRESS)), a -> a.name("addresses") .getter(Person::getAddresses) .setter(Person::setAddresses)) .addAttribute(EnhancedType.listOf( // 2. Use mapping functionality of the PhoneNumber table schema. EnhancedType.documentOf(PhoneNumber.class, TABLE_SCHEMA_PHONENUMBER)), a -> a.name("phoneNumbers") .getter(Person::getPhoneNumbers) .setter(Person::setPhoneNumbers)) .build();

Projektattribute komplexer Typen

Für query() und scan() Methoden können Sie mithilfe von Methodenaufrufen wie addNestedAttributeToProject() und angeben, welche Attribute in den Ergebnissen zurückgegeben werden sollenattributesToProject(). Der DynamoDB Enhanced Client API konvertiert die Parameter des Java-Methodenaufrufs in Projektionsausdrücke, bevor die Anforderung gesendet wird.

Das folgende Beispiel füllt die Person Tabelle mit zwei Elementen und führt dann drei Scanvorgänge durch.

Beim ersten Scan werden alle Elemente in der Tabelle abgerufen, um die Ergebnisse mit den anderen Scanvorgängen zu vergleichen.

Der zweite Scan verwendet die addNestedAttributeToProject()Builder-Methode, um nur den street Attributwert zurückzugeben.

Der dritte Scanvorgang verwendet die attributesToProject()Builder-Methode, um die Daten für das Attribut der ersten Ebene zurückzugeben,hobbies. Der Attributtyp von hobbies ist eine Liste. Um auf einzelne Listenelemente zuzugreifen, führen Sie einen get() Vorgang in der Liste aus.

personDynamoDbTable = getDynamoDbEnhancedClient().table("Person", PERSON_TABLE_SCHEMA); PersonUtils.createPersonTable(personDynamoDbTable, getDynamoDbClient()); // Use a utility class to add items to the Person table. List<Person> personList = PersonUtils.getItemsForCount(2); // This utility method performs a put against DynamoDB to save the instances in the list argument. PersonUtils.putCollection(getDynamoDbEnhancedClient(), personList, personDynamoDbTable); // The first scan logs all items in the table to compare to the results of the subsequent scans. final PageIterable<Person> allItems = personDynamoDbTable.scan(); allItems.items().forEach(p -> // 1. Log what is in the table. logger.info(p.toString())); // Scan for nested attributes. PageIterable<Person> streetScanResult = personDynamoDbTable.scan(b -> b // Use the 'addNestedAttributeToProject()' or 'addNestedAttributesToProject()' to access data nested in maps in DynamoDB. .addNestedAttributeToProject( NestedAttributeName.create("addresses", "work", "street") )); streetScanResult.items().forEach(p -> //2. Log the results of requesting nested attributes. logger.info(p.toString())); // Scan for a top-level list attribute. PageIterable<Person> hobbiesScanResult = personDynamoDbTable.scan(b -> b // Use the 'attributesToProject()' method to access first-level attributes. .attributesToProject("hobbies")); hobbiesScanResult.items().forEach((p) -> { // 3. Log the results of the request for the 'hobbies' attribute. logger.info(p.toString()); // To access an item in a list, first get the parent attribute, 'hobbies', then access items in the list. String hobby = p.getHobbies().get(1); // 4. Log an item in the list. logger.info(hobby); });
// Logged results from comment line 1. Person{id=2, firstName='first name 2', lastName='last name 2', age=11, addresses={work=Address{street='street 21', city='city 21', state='state 21', zipCode='33333'}, home=Address{street='street 2', city='city 2', state='state 2', zipCode='22222'}}, phoneNumbers=[PhoneNumber{type='home', number='222-222-2222'}, PhoneNumber{type='work', number='333-333-3333'}], hobbies=[hobby 2, hobby 21]} Person{id=1, firstName='first name 1', lastName='last name 1', age=11, addresses={work=Address{street='street 11', city='city 11', state='state 11', zipCode='22222'}, home=Address{street='street 1', city='city 1', state='state 1', zipCode='11111'}}, phoneNumbers=[PhoneNumber{type='home', number='111-111-1111'}, PhoneNumber{type='work', number='222-222-2222'}], hobbies=[hobby 1, hobby 11]} // Logged results from comment line 2. Person{id=null, firstName='null', lastName='null', age=null, addresses={work=Address{street='street 21', city='null', state='null', zipCode='null'}}, phoneNumbers=null, hobbies=null} Person{id=null, firstName='null', lastName='null', age=null, addresses={work=Address{street='street 11', city='null', state='null', zipCode='null'}}, phoneNumbers=null, hobbies=null} // Logged results from comment lines 3 and 4. Person{id=null, firstName='null', lastName='null', age=null, addresses=null, phoneNumbers=null, hobbies=[hobby 2, hobby 21]} hobby 21 Person{id=null, firstName='null', lastName='null', age=null, addresses=null, phoneNumbers=null, hobbies=[hobby 1, hobby 11]} hobby 11
Anmerkung

Wenn die attributesToProject() Methode einer anderen Builder-Methode folgt, die Attribute hinzufügt, die Sie projizieren möchten, attributesToProject() ersetzt die mitgelieferte Liste der Attributnamen alle anderen Attributnamen.

Ein Scan, der mit der ScanEnhancedRequest Instanz im folgenden Codeausschnitt durchgeführt wird, gibt nur Hobbydaten zurück.

ScanEnhancedRequest lastOverwrites = ScanEnhancedRequest.builder() .addNestedAttributeToProject( NestedAttributeName.create("addresses", "work", "street")) .addAttributeToProject("firstName") // If the 'attributesToProject()' method follows other builder methods that add attributes for projection, // its list of attributes replace all previous attributes. .attributesToProject("hobbies") .build(); PageIterable<Person> hobbiesOnlyResult = personDynamoDbTable.scan(lastOverwrites); hobbiesOnlyResult.items().forEach(p -> logger.info(p.toString())); // Logged results. Person{id=null, firstName='null', lastName='null', age=null, addresses=null, phoneNumbers=null, hobbies=[hobby 2, hobby 21]} Person{id=null, firstName='null', lastName='null', age=null, addresses=null, phoneNumbers=null, hobbies=[hobby 1, hobby 11]}

Der folgende Codeausschnitt verwendet die Methode zuerst. attributesToProject() Bei dieser Reihenfolge werden alle anderen angeforderten Attribute beibehalten.

ScanEnhancedRequest attributesPreserved = ScanEnhancedRequest.builder() // Use 'attributesToProject()' first so that the method call does not replace all other attributes // that you want to project. .attributesToProject("firstName") .addNestedAttributeToProject( NestedAttributeName.create("addresses", "work", "street")) .addAttributeToProject("hobbies") .build(); PageIterable<Person> allAttributesResult = personDynamoDbTable.scan(attributesPreserved); allAttributesResult.items().forEach(p -> logger.info(p.toString())); // Logged results. Person{id=null, firstName='first name 2', lastName='null', age=null, addresses={work=Address{street='street 21', city='null', state='null', zipCode='null'}}, phoneNumbers=null, hobbies=[hobby 2, hobby 21]} Person{id=null, firstName='first name 1', lastName='null', age=null, addresses={work=Address{street='street 11', city='null', state='null', zipCode='null'}}, phoneNumbers=null, hobbies=[hobby 1, hobby 11]}

Verwenden Sie komplexe Typen in Ausdrücken

Sie können komplexe Typen in Ausdrücken wie Filterausdrücken und Bedingungsausdrücken verwenden, indem Sie Dereferenzierungsoperatoren verwenden, um in der Struktur des komplexen Typs zu navigieren. Verwenden Sie für Objekte und Maps das . (dot) und für Listenelemente use [n] (eckige Klammern um die Sequenznummer des Elements). Sie können nicht auf einzelne Elemente einer Menge verweisen, aber Sie können die containsFunktion verwenden.

Das folgende Beispiel zeigt zwei Filterausdrücke, die bei Scanvorgängen verwendet werden. Die Filterausdrücke geben die Übereinstimmungsbedingungen für Elemente an, die Sie in den Ergebnissen haben möchten. In dem Beispiel werden Person die zuvor gezeigten PhoneNumber KlassenAddress, und verwendet.

public void scanUsingFilterOfNestedAttr() { // The following is a filter expression for an attribute that is a map of Address objects. // By using this filter expression, the SDK returns Person objects that have an address // with 'mailing' as a key and 'MS2' for a state value. Expression addressFilter = Expression.builder() .expression("addresses.#type.#field = :value") .putExpressionName("#type", "mailing") .putExpressionName("#field", "state") .putExpressionValue(":value", AttributeValue.builder().s("MS2").build()) .build(); PageIterable<Person> addressFilterResults = personDynamoDbTable.scan(rb -> rb. filterExpression(addressFilter)); addressFilterResults.items().stream().forEach(p -> logger.info("Person: {}", p)); assert addressFilterResults.items().stream().count() == 1; // The following is a filter expression for an attribute that is a list of phone numbers. // By using this filter expression, the SDK returns Person objects whose second phone number // in the list has a type equal to 'cell'. Expression phoneFilter = Expression.builder() .expression("phoneNumbers[1].#type = :type") .putExpressionName("#type", "type") .putExpressionValue(":type", AttributeValue.builder().s("cell").build()) .build(); PageIterable<Person> phoneFilterResults = personDynamoDbTable.scan(rb -> rb .filterExpression(phoneFilter) .attributesToProject("id", "firstName", "lastName", "phoneNumbers") ); phoneFilterResults.items().stream().forEach(p -> logger.info("Person: {}", p)); assert phoneFilterResults.items().stream().count() == 1; assert phoneFilterResults.items().stream().findFirst().get().getPhoneNumbers().get(1).getType().equals("cell"); }
public static void populateDatabase() { Person person1 = new Person(); person1.setId(1); person1.setFirstName("FirstName1"); person1.setLastName("LastName1"); Address billingAddr1 = new Address(); billingAddr1.setState("BS1"); billingAddr1.setCity("BillingTown1"); Address mailing1 = new Address(); mailing1.setState("MS1"); mailing1.setCity("MailingTown1"); person1.setAddresses(Map.of("billing", billingAddr1, "mailing", mailing1)); PhoneNumber pn1_1 = new PhoneNumber(); pn1_1.setType("work"); pn1_1.setNumber("111-111-1111"); PhoneNumber pn1_2 = new PhoneNumber(); pn1_2.setType("home"); pn1_2.setNumber("222-222-2222"); List<PhoneNumber> phoneNumbers1 = List.of(pn1_1, pn1_2); person1.setPhoneNumbers(phoneNumbers1); personDynamoDbTable.putItem(person1); Person person2 = person1; person2.setId(2); person2.setFirstName("FirstName2"); person2.setLastName("LastName2"); Address billingAddress2 = billingAddr1; billingAddress2.setCity("BillingTown2"); billingAddress2.setState("BS2"); Address mailing2 = mailing1; mailing2.setCity("MailingTown2"); mailing2.setState("MS2"); person2.setAddresses(Map.of("billing", billingAddress2, "mailing", mailing2)); PhoneNumber pn2_1 = new PhoneNumber(); pn2_1.setType("work"); pn2_1.setNumber("333-333-3333"); PhoneNumber pn2_2 = new PhoneNumber(); pn2_2.setType("cell"); pn2_2.setNumber("444-444-4444"); List<PhoneNumber> phoneNumbers2 = List.of(pn2_1, pn2_2); person2.setPhoneNumbers(phoneNumbers2); personDynamoDbTable.putItem(person2); }
{ "id": 1, "addresses": { "billing": { "city": "BillingTown1", "state": "BS1", "street": null, "zipCode": null }, "mailing": { "city": "MailingTown1", "state": "MS1", "street": null, "zipCode": null } }, "firstName": "FirstName1", "lastName": "LastName1", "phoneNumbers": [ { "number": "111-111-1111", "type": "work" }, { "number": "222-222-2222", "type": "home" } ] } { "id": 2, "addresses": { "billing": { "city": "BillingTown2", "state": "BS2", "street": null, "zipCode": null }, "mailing": { "city": "MailingTown2", "state": "MS2", "street": null, "zipCode": null } }, "firstName": "FirstName2", "lastName": "LastName2", "phoneNumbers": [ { "number": "333-333-3333", "type": "work" }, { "number": "444-444-4444", "type": "cell" } ] }

Aktualisieren Sie Elemente, die komplexe Typen enthalten

Um ein Element zu aktualisieren, das komplexe Typen enthält, haben Sie zwei grundlegende Methoden:

  • Ansatz 1: Rufen Sie zuerst das Element ab (mithilfe vongetItem), aktualisieren Sie das Objekt und rufen Sie es dann aufDynamoDbTable#updateItem.

  • Ansatz 2: Rufen Sie das Element nicht ab, sondern erstellen Sie eine neue Instanz, legen Sie die Eigenschaften fest, die Sie aktualisieren möchten, und leiten Sie die Instanz weiter, DynamoDbTable#updateItem indem Sie den entsprechenden Wert von festlegen IgnoreNullsMode. Bei diesem Ansatz müssen Sie das Element nicht abrufen, bevor Sie es aktualisieren.

Die in diesem Abschnitt gezeigten Beispiele verwenden die zuvor aufgeführten PhoneNumber Klassen PersonAddress, und.

Aktualisierungsansatz 1: Abrufen, dann aktualisieren

Mit diesem Ansatz stellen Sie sicher, dass beim Update keine Daten verloren gehen. Der DynamoDB Enhanced Client API erstellt die Bean mit den Attributen des in DynamoDB gespeicherten Elements neu, einschließlich Werten komplexer Typen. Anschließend müssen Sie die Getter und Setter verwenden, um die Bean zu aktualisieren. Der Nachteil dieses Ansatzes sind die Kosten, die Ihnen entstehen, wenn Sie den Artikel zuerst abrufen.

Das folgende Beispiel zeigt, dass keine Daten verloren gehen, wenn Sie das Element zuerst abrufen, bevor Sie es aktualisieren.

public void retrieveThenUpdateExample() { // Assume that we ran this code yesterday. Person person = new Person(); person.setId(1); person.setFirstName("FirstName"); person.setLastName("LastName"); Address mainAddress = new Address(); mainAddress.setStreet("123 MyStreet"); mainAddress.setCity("MyCity"); mainAddress.setState("MyState"); mainAddress.setZipCode("MyZipCode"); person.setMainAddress(mainAddress); PhoneNumber homePhone = new PhoneNumber(); homePhone.setNumber("1111111"); homePhone.setType("HOME"); person.setPhoneNumbers(List.of(homePhone)); personDynamoDbTable.putItem(person); // Assume that we are running this code now. // First, retrieve the item Person retrievedPerson = personDynamoDbTable.getItem(Key.builder().partitionValue(1).build()); // Make any updates. retrievedPerson.getMainAddress().setCity("YourCity"); // Save the updated bean. 'updateItem' returns the bean as it appears after the update. Person updatedPerson = personDynamoDbTable.updateItem(retrievedPerson); // Verify for this example. Address updatedMainAddress = updatedPerson.getMainAddress(); assert updatedMainAddress.getCity().equals("YourCity"); assert updatedMainAddress.getState().equals("MyState"); // Unchanged. // The list of phone numbers remains; it was not set to null; assert updatedPerson.getPhoneNumbers().size() == 1; }

Aktualisierungsansatz 2: Verwenden Sie eine IgnoreNullsMode Aufzählung, ohne das Element zuerst abzurufen

Um ein Element in DynamoDB zu aktualisieren, können Sie ein neues Objekt angeben, das nur die Eigenschaften hat, die Sie aktualisieren möchten, und die anderen Werte auf Null belassen. Bei diesem Ansatz müssen Sie wissen, wie Nullwerte im Objekt von der behandelt werden SDK und wie Sie das Verhalten steuern können.

Um anzugeben, welche Eigenschaften mit Nullwerten Sie ignorieren SDK möchten, geben Sie beim Erstellen von eine IgnoreNullsMode Aufzählung an. UpdateItemEnhancedRequest Als Beispiel für die Verwendung eines der Aufzählungswerte verwendet der folgende Codeausschnitt den Modus. IgnoreNullsMode.SCALAR_ONLY

// Create a new Person object to update the existing item in DynamoDB. Person personForUpdate = new Person(); personForUpdate.setId(1); personForUpdate.setFirstName("updatedFirstName"); // 'firstName' is a top scalar property. Address addressForUpdate = new Address(); addressForUpdate.setCity("updatedCity"); personForUpdate.setMainAddress(addressForUpdate); personDynamoDbTable.updateItem(r -> r .item(personForUpdate) .ignoreNullsMode(IgnoreNullsMode.SCALAR_ONLY) .build()); /* With IgnoreNullsMode.SCALAR_ONLY provided, The SDK ignores all null properties. The SDK adds or replaces the 'firstName' property with the provided value, "updatedFirstName". The SDK updates the 'city' value of 'mainAddress', as long as the 'mainAddress' attribute already exists in DynamoDB. In the background, the SDK generates an update expression that it sends in the request to DynamoDB. The following JSON object is a simplified version of what it sends. Notice that the SDK includes the paths to 'mainAddress.city' and 'firstName' in the SET clause of the update expression. No null values in 'personForUpdate' are included. { "TableName": "PersonTable", "Key": { "id": { "N": "1" } }, "ReturnValues": "ALL_NEW", "UpdateExpression": "SET #mainAddress.#city = :mainAddress_city, #firstName = :firstName", "ExpressionAttributeNames": { "#city": "city", "#firstName": "firstName", "#mainAddress": "mainAddress" }, "ExpressionAttributeValues": { ":firstName": { "S": "updatedFirstName" }, ":mainAddress_city": { "S": "updatedCity" } } } Had we chosen 'IgnoreNullsMode.DEFAULT' instead of 'IgnoreNullsMode.SCALAR_ONLY', the SDK would have included null values in the "ExpressionAttributeValues" section of the request as shown in the following snippet. "ExpressionAttributeValues": { ":mainAddress": { "M": { "zipCode": { "NULL": true }, "city": { "S": "updatedCity" }, "street": { "NULL": true }, "state": { "NULL": true } } }, ":firstName": { "S": "updatedFirstName" } } */

Das Amazon DynamoDB Developer Guide enthält weitere Informationen zu Aktualisierungsausdrücken.

Beschreibungen der Optionen IgnoreNullsMode

  • IgnoreNullsMode.SCALAR_ONLY- Verwenden Sie diese Einstellung, um skalare Attribute auf einer beliebigen Ebene zu aktualisieren. Der SDK konstruiert eine Aktualisierungsanweisung, die nur skalare Attribute ungleich Null an DynamoDB sendet. Das SDK ignoriert nullwertige, skalare Attribute einer Bean oder Map und behält den gespeicherten Wert in DynamoDB bei.

    Wenn Sie ein skalares Attribut von map oder bean aktualisieren, muss die Map bereits in DynamoDB vorhanden sein. Wenn Sie dem Objekt eine Map oder eine Bean hinzufügen, die noch nicht für das Objekt in DynamoDB vorhanden ist, erhalten Sie eine DynamoDbException mit der Meldung Der im Aktualisierungsausdruck angegebene Dokumentpfad ist für die Aktualisierung ungültig. Sie müssen MAPS_ONLY den Modus verwenden, um DynamoDB ein Bean oder eine Map hinzuzufügen, bevor Sie eines ihrer Attribute aktualisieren.

  • IgnoreNullsMode.MAPS_ONLY- Verwenden Sie diese Einstellung, um Eigenschaften hinzuzufügen oder zu ersetzen, bei denen es sich um eine Bean oder Map handelt. Dadurch werden alle im Objekt bereitgestellten Maps oder Beans SDK ersetzt oder hinzugefügt. Alle Beans oder Maps, die im Objekt Null sind, werden ignoriert, wobei die in DynamoDB vorhandene Map beibehalten wird.

  • IgnoreNullsMode.DEFAULT- Bei dieser Einstellung ignoriert der SDK niemals Nullwerte. Skalare Attribute auf jeder Ebene, die Null sind, werden auf Null aktualisiert. Dadurch werden alle Bean-, Map-, List- oder Set-Eigenschaften mit Nullwert im Objekt in DynamoDB auf Null SDK aktualisiert. Wenn Sie diesen Modus verwenden — oder keinen Modus angeben, da es der Standardmodus ist — sollten Sie das Element zuerst abrufen, damit Werte in DynamoDB nicht auf Null gesetzt werden, die im Objekt zur Aktualisierung bereitgestellt werden, es sei denn, Sie beabsichtigen, die Werte auf Null zu setzen.

Wenn Sie in allen Modi ein Objekt mit einer Liste oder einem Satz angebenupdateItem, der nicht Null ist, wird die Liste oder der Satz in DynamoDB gespeichert.

Warum die Modi?

Wenn Sie ein Objekt mit einem Bean oder einer Map für die updateItem Methode angeben, SDK können sie nicht sagen, ob es die Eigenschaftswerte in der Bean (oder die Eingabewerte in der Map) verwenden soll, um das Element zu aktualisieren, oder ob die gesamte Bean/Map das ersetzen soll, was in DynamoDB gespeichert wurde.

Ausgehend von unserem vorherigen Beispiel, das zuerst den Abruf des Elements zeigt, versuchen wir, das city Attribut von ohne den Abruf zu aktualisieren. mainAddress

/* The retrieval example saved the Person object with a 'mainAddress' property whose 'city' property value is "MyCity". /* Note that we create a new Person with only the necessary information to update the city value of the mainAddress. */ Person personForUpdate = new Person(); personForUpdate.setId(1); // The update we want to make changes the city. Address mainAddressForUpdate = new Address(); mainAddressForUpdate.setCity("YourCity"); personForUpdate.setMainAddress(mainAddressForUpdate); // Lets' try the following: Person updatedPerson = personDynamoDbTable.updateItem(personForUpdate); /* Since we haven't retrieved the item, we don't know if the 'mainAddress' property already exists, so what update expression should the SDK generate? A) Should it replace or add the 'mainAddress' with the provided object (setting all attributes to null other than city) as shown in the following simplified JSON? { "TableName": "PersonTable", "Key": { "id": { "N": "1" } }, "ReturnValues": "ALL_NEW", "UpdateExpression": "SET #mainAddress = :mainAddress", "ExpressionAttributeNames": { "#mainAddress": "mainAddress" }, "ExpressionAttributeValues": { ":mainAddress": { "M": { "zipCode": { "NULL": true }, "city": { "S": "YourCity" }, "street": { "NULL": true }, "state": { "NULL": true } } } } } B) Or should it update only the 'city' attribute of an existing 'mainAddress' as shown in the following simplified JSON? { "TableName": "PersonTable", "Key": { "id": { "N": "1" } }, "ReturnValues": "ALL_NEW", "UpdateExpression": "SET #mainAddress.#city = :mainAddress_city", "ExpressionAttributeNames": { "#city": "city", "#mainAddress": "mainAddress" }, "ExpressionAttributeValues": { ":mainAddress_city": { "S": "YourCity" } } } However, assume that we don't know if the 'mainAddress' already exists. If it doesn't exist, the SDK would try to update an attribute of a non-existent map, which results in an exception. In this particular case, we would likely select option B (SCALAR_ONLY) to retain the other values of the 'mainAddress'. */

Die folgenden beiden Beispiele zeigen die Verwendung von Werten MAPS_ONLY und SCALAR_ONLY Aufzählungswerten. MAPS_ONLYfügt eine Map hinzu und SCALAR_ONLY aktualisiert eine Map.

public void mapsOnlyModeExample() { // Assume that we ran this code yesterday. Person person = new Person(); person.setId(1); person.setFirstName("FirstName"); personDynamoDbTable.putItem(person); // Assume that we are running this code now. /* Note that we create a new Person with only the necessary information to update the city value of the mainAddress. */ Person personForUpdate = new Person(); personForUpdate.setId(1); // The update we want to make changes the city. Address mainAddressForUpdate = new Address(); mainAddressForUpdate.setCity("YourCity"); personForUpdate.setMainAddress(mainAddressForUpdate); Person updatedPerson = personDynamoDbTable.updateItem(r -> r .item(personForUpdate) .ignoreNullsMode(IgnoreNullsMode.MAPS_ONLY)); // Since the mainAddress property does not exist, use MAPS_ONLY mode. assert updatedPerson.getMainAddress().getCity().equals("YourCity"); assert updatedPerson.getMainAddress().getState() == null; }
public void scalarOnlyExample() { // Assume that we ran this code yesterday. Person person = new Person(); person.setId(1); Address mainAddress = new Address(); mainAddress.setCity("MyCity"); mainAddress.setState("MyState"); person.setMainAddress(mainAddress); personDynamoDbTable.putItem(person); // Assume that we are running this code now. /* Note that we create a new Person with only the necessary information to update the city value of the mainAddress. */ Person personForUpdate = new Person(); personForUpdate.setId(1); // The update we want to make changes the city. Address mainAddressForUpdate = new Address(); mainAddressForUpdate.setCity("YourCity"); personForUpdate.setMainAddress(mainAddressForUpdate); Person updatedPerson = personDynamoDbTable.updateItem(r -> r .item(personForUpdate) .ignoreNullsMode(IgnoreNullsMode.SCALAR_ONLY)); // SCALAR_ONLY mode ignores null properties in the in mainAddress. assert updatedPerson.getMainAddress().getCity().equals("YourCity"); assert updatedPerson.getMainAddress().getState().equals("MyState"); // The state property remains the same. }

In der folgenden Tabelle können Sie nachlesen, welche Nullwerte für jeden Modus ignoriert werden. Sie können oft mit beiden SCALAR_ONLY arbeiten, MAPS_ONLY außer wenn Sie mit Beans oder Maps arbeiten.

Welche nullwertigen Eigenschaften des Objekts, an das übergeben wurde, werden für jeden Modus SDK ignoriertupdateItem?
Art der Immobilie im ONLY Modus SCALAR _ im ONLY Modus MAPS _ im DEFAULT Modus
Oberster Skalar Ja Ja Nein
Bean oder Karte Ja Ja Nein
Skalarwert eines Bean- oder Map-Eintrags Ja1 Nein 2 Nein
Liste oder Satz Ja Ja Nein

1 Dies setzt voraus, dass die Map bereits in DynamoDB vorhanden ist. Jeder Skalarwert — Null oder nicht Null — der Bean oder Map, die Sie im Objekt für die Aktualisierung angeben, erfordert, dass ein Pfad zu dem Wert in DynamoDB existiert. Der SDK erstellt mithilfe des Dereferenzierungsoperators einen Pfad zu dem Attribut, bevor er die Anforderung sendet. . (dot)

2 Da Sie den MAPS_ONLY Modus verwenden, um eine Bean oder Map vollständig zu ersetzen oder hinzuzufügen, werden alle Nullwerte in der Bean oder Map in der in DynamoDB gespeicherten Map beibehalten.