Home >Backend Development >Golang >Unmarshalling dynamodb projects returns the same project

Unmarshalling dynamodb projects returns the same project

PHPz
PHPzforward
2024-02-08 23:00:111058browse

解组 dynamodb 项目返回相同的项目

php editor Zimo will introduce to you today how to solve the problem of ungrouping DynamoDB items and returning the same items. DynamoDB is a high-performance, serverless key-value database, but sometimes it may return the same items when querying them, which can be a tricky problem for developers. Don't worry, we'll provide you with a solution to ensure your query results are unique and correct. In this article, we will explain the cause of the problem in detail and provide a simple and effective way to solve it. Let’s take a look!

Question content

I have a range loop in golang that loops through the mapping of type.attributevalues returned by dynamodb using a scan function.

I'm looping through this map using the built-in function provided by the golang aws-sdk-v2 package attributevalue.unmarshalmap() and what happens is that I get back items that are the same length as the slice.

Code:

type users struct {
    user *string `dynamodbav:"user"` 
    email *string `dynamodbav:"email"` 
    }

    user := users{}
  
   for _ , dbitem := range dynamoresults.items { 
    err = attributevalue.unmarshalmap(dbitem, &user)
   }

// gives the same pointer location for all 
users[0].user 
users[1].user
users[2].user

I also tried appending the user to the slice in the results

// this just gives a slice with the same items as above
 u := []Users{}
for _ , dbItem := range dynamoResults.Items { 
        err = attributevalue.UnmarshalMap(dbItem, &Users)
        u = append(u, Users)
       }

The solution I found using attributevalue.unmarshallistofmaps() is to simply provide the function with a slice of items from dynamodb.

My question is actually to understand why using the above two solutions doesn't work as expected, doesn't it loop through the dynamodb items and pass them individually to the unmarshal function? It seems like just keep doing the same thing.

Solution

If we change the problem slightly - from dynamo db unmarshalling to json unmarshalling - then we can go playground. In the sample code, I see two factors working together to cause duplicate slice values:

  1. The unmarshalling target is defined outside the loop (line 51), so when unmarshalling u1out, the result is written to the same location on each loop iteration (line 54) .

  2. The field of type
  3. user1 is *string, so when the loop variable value is copied to the slice (line 55), user and email The string pointed to will not be copied. Only their pointer values ​​are copied.

Putting these two together, each iteration will write the unmarshaled user and email values ​​to the same memory location. This is demonstrated by the first two lines of output, which print the elements of u1out.

The remaining lines of output show the results in three other cases: when the target variable is moved within the loop (u1in and u2in) or when the field is changed to string(u2out). In each case, new locations for ungrouped values ​​are created as expected, and duplicates are not printed.

package main

import (
    "encoding/json"
    "fmt"
)

type (
    Users1 struct {
        User  *string
        Email *string
    }
    Users2 struct {
        User  string
        Email string
    }
)

func main() {
    dbItems := []string{
        `{"User":"userA","Email":"<a href="https://www.php.cn/link/89fee0513b6668e555959f5dc23238e9" class="__cf_email__" data-cfemail="a7d2d4c2d5e6e7c2dfc6cad7cbc289c4c8ca">[email&#160;protected]</a>"}`,
        `{"User":"userB","Email":"<a href="https://www.php.cn/link/89fee0513b6668e555959f5dc23238e9" class="__cf_email__" data-cfemail="5a2f293f28181a3f223b372a363f74393537">[email&#160;protected]</a>"}`,
    }

    u1Out := withVarDeclaredOutsideLoop[Users1](dbItems)
    printUsers(u1Out)

    u1In := withVarDeclaredInsideLoop[Users1](dbItems)
    printUsers(u1In)

    u2Out := withVarDeclaredOutsideLoop[Users2](dbItems)
    printUsers(u2Out)

    u2In := withVarDeclaredInsideLoop[Users2](dbItems)
    printUsers(u2In)

    // Output
    // u[0] = {User:0xc000014130 Email:0xc000014140}
    // u[1] = {User:0xc000014130 Email:0xc000014140}
    // u[0] = {User:0xc0000141c0 Email:0xc0000141d0}
    // u[1] = {User:0xc000014210 Email:0xc000014220}
    // u[0] = {User:userA Email:<a href="https://www.php.cn/link/89fee0513b6668e555959f5dc23238e9" class="__cf_email__" data-cfemail="86f3f5e3f4c7c6e3fee7ebf6eae3a8e5e9eb">[email&#160;protected]</a>}
    // u[1] = {User:userB Email:<a href="https://www.php.cn/link/89fee0513b6668e555959f5dc23238e9" class="__cf_email__" data-cfemail="07727462754547627f666a776b622964686a">[email&#160;protected]</a>}
    // u[0] = {User:userA Email:<a href="https://www.php.cn/link/89fee0513b6668e555959f5dc23238e9" class="__cf_email__" data-cfemail="98edebfdead9d8fde0f9f5e8f4fdb6fbf7f5">[email&#160;protected]</a>}
    // u[1] = {User:userB Email:<a href="https://www.php.cn/link/89fee0513b6668e555959f5dc23238e9" class="__cf_email__" data-cfemail="fe8b8d9b8cbcbe9b869f938e929bd09d9193">[email&#160;protected]</a>}
}

func withVarDeclaredOutsideLoop[T any](dbItems []string) []T {
    var t T
    u := []T{}
    for _, dbItem := range dbItems {
        json.Unmarshal([]byte(dbItem), &t)
        u = append(u, t)
    }
    return u
}

func withVarDeclaredInsideLoop[T any](dbItems []string) []T {
    u := []T{}
    for _, dbItem := range dbItems {
        var t T
        json.Unmarshal([]byte(dbItem), &t)
        u = append(u, t)
    }
    return u
}

func printUsers[T any](u []T) {
    for i, user := range u {
        fmt.Printf("u[%d] = %+v\n", i, user)
    }
}

The above is the detailed content of Unmarshalling dynamodb projects returns the same project. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete