I have several JSON's of the same structure. They have object that is an array of objects . How to I append these arrays into one array?

huangapple go评论73阅读模式
英文:

I have several JSON's of the same structure. They have object that is an array of objects . How to I append these arrays into one array?

问题

我想做的事情:

我想向以下URL发送多个GET请求:
https://catalog.wb.ru/brands/m/catalog?page=1&limit=300&brand=5786&dest=-1257786&sort=pricedown
然后收集“product”对象内的所有数据。键“PAGE”的值是自动递增的,以获取所有页面的数据。

实际上,我不太确定是否真的需要构建一个JSON对象并将其发送到前端。也许在for循环中收到新的响应时,逐个发送不同的请求会更好?

我所做的:

创建了requestBodyBytes []byteProductsBytes []byte,以便将它们与ioutil.ReadAll[]bytes附加在一起。
打印requestBodyBytes的长度,我发现它随着每个请求的增加而扩展,但在我解组后,输出中看到空的结构体。

我明白这是因为每个单独的请求我都会得到type Response的新JSON。但是,如果我需要一个由多个type Response的JSON组成的“product”对象的切片呢?

注意:需要在for循环中初始化requestBodyBytes,以便在页面上没有信息时使用它停止发送请求,因为服务器会返回200代码和空JSON。

提前谢谢!

const URL = "https://catalog.wb.ru/brands/m/catalog?page=%d&limit=300&brand=5786&dest=-1257786&sort=pricedown"

type Response struct {
	Data struct {
		Products []Product `json:"products"`
	} `json:"data"`
}

type Product struct {
	ID     int     `json:"id"`
	Name   string  `json:"name"`
	Price  int     `json:"priceU"`
	Rating float32 `json:"reviewRating"`
	Sale   int     `json:"sale"`
	New    bool    `json:"isNew"`
}

func main() {
	var response Response
	var products Response //也尝试将其定义为[]Response
	var ProductsBytes []byte

	for i := 1; ; i++ {
		resp, err := http.Get(fmt.Sprintf(URL, i))
		if err != nil {
			fmt.Printf("#1 Error: %s", err)
		}
		defer resp.Body.Close()

		bytes, err := ioutil.ReadAll(resp.Body)
		var requestBodyBytes []byte
		requestBodyBytes = append(requestBodyBytes, bytes...)
		ProductsBytes = append(ProductsBytes, bytes...)

		json.Unmarshal(requestBodyBytes, &response)

		fmt.Println(resp.Status)
		fmt.Printf("\n来自第%d页的切片\n字节长度:%d\n", i, len(bytes))
		fmt.Printf("finalResult的长度:%d\n", len(requestBodyBytes))
		if len(response.Data.Products) == 0 {
			fmt.Println("没有更多数据")
			break
		}
	}

	json.Unmarshal(ProductsBytes, &products)

	fmt.Println(response)
	fmt.Println(products)
	fmt.Println(len(products))
}

英文:

What I want to do:

I want to send several GET-requests to this URL:
https://catalog.wb.ru/brands/m/catalog?page=1&limit=300&brand=5786&dest=-1257786&sort=pricedown
Then gather all the data inside of a "product" object. The value of key "PAGE" is autoincrementing to get data from all pages.

Actually I'm not quite sure that I really need to make up one JSON to send it to front-end. Maybe it's better to send different requests as I get new responses in a for loop?

What I did:

Made correct structures. With single request everything is working fine.

Created requestBodyBytes []byte and ProductsBytes []byte in order to append them with []bytes from ioutil.ReadAll.
Printing length of requestBodyBytes I see that it expands with every request but after I Unmarshal it I see empty struct in the output.

I understand that it happens because every single request I get new JSON of type Response. But what if I need a slice of Product structs composed of "product" objects from several JSON's of type Response?

Note: needed to init requestBodyBytes inside of for loop to use it to stop sending requests because the server gives 200 code and empty JSON when there's no information on a page.

Thank you in advance!

const URL = "https://catalog.wb.ru/brands/m/catalog?page=%d&limit=300&brand=5786&dest=-1257786&sort=pricedown"
type Response struct {
Data struct {
Products []Product `json:"products"`
} `json:"data"`
}
type Product struct {
ID     int     `json:"id"`
Name   string  `json:"name"`
Price  int     `json:"priceU"`
Rating float32 `json:"reviewRating"`
Sale   int     `json:"sale"`
New    bool    `json:"isNew"`
}
func main() {
var response Response
var products Response //Also tried to make it []Response
var ProductsBytes []byte
for i := 1; ; i++ {
resp, err := http.Get(fmt.Sprintf(URL, i))
if err != nil {
fmt.Printf("#1 Error: %s", err)
}
defer resp.Body.Close()
bytes, err := ioutil.ReadAll(resp.Body)
var requestBodyBytes []byte
requestBodyBytes = append(requestBodyBytes, bytes...)
ProductsBytes = append(ProductsBytes, bytes...)
json.Unmarshal(requestBodyBytes, &response)
fmt.Println(resp.Status)
fmt.Printf("\nSlice from page #%d\nLength of bytes: %d\n", i, len(bytes))
fmt.Printf("Length of finalResult: %d\n", len(requestBodyBytes))
if len(response.Data.Products) == 0 {
fmt.Println("There's no more data")
break
}
}
json.Unmarshal(ProductsBytes, &products)
fmt.Println(response)
fmt.Println(products)
fmt.Println(len(products))
}

答案1

得分: 2

没有理由收集所有原始响应字节。只需逐个解组每个响应,并将每个页面的产品追加到保存所有产品的切片中。此外,在循环中调用defer resp.Body.Close()可能不是你想要的。延迟语句只在循环结束后执行,因此无法重用连接进行请求。将循环体提取到自己的函数中可以使代码更清晰:

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
)

const URL = "https://catalog.wb.ru/brands/m/catalog?page=%d&limit=300&brand=5786&dest=-1257786&sort=pricedown"

type Response struct {
	Data struct {
		Products []Product `json:"products"`
	} `json:"data"`
}

type Product struct {
	ID     int     `json:"id"`
	Name   string  `json:"name"`
	Price  int     `json:"priceU"`
	Rating float32 `json:"reviewRating"`
	Sale   int     `json:"sale"`
	New    bool    `json:"isNew"`
}

func main() {
	var allProducts []Product

	for i := 1; ; i++ {
		page, err := fetchPage(i)
		if err != nil {
			log.Fatal(err) // TODO
		}

		allProducts = append(allProducts, page...)

		if len(page) == 0 {
			break
		}
	}

	fmt.Println(allProducts)
	fmt.Println(len(allProducts))
}

func fetchPage(i int) ([]Product, error) {
	resp, err := http.Get(fmt.Sprintf(URL, i))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return nil, errors.New(resp.Status)
	}

	var response Response
	err = json.NewDecoder(resp.Body).Decode(&response)
	if err != nil {
		return nil, err
	}

	return response.Data.Products, nil
}

英文:

There is no reason to collect all the raw response bytes. Just unmarshal each response individually and append the products for each page to some slice holding all of the products. Also, calling defer resp.Body.Close() in a loop is probably not what you want. The deferred statement executes only after the loop finishes, so connections cannot be re-used for the requests. Extracting the loop body into its own function makes this much cleaner:

package main
import (
"encoding/json"
"errors"
"fmt"
"log"
"net/http"
)
const URL = "https://catalog.wb.ru/brands/m/catalog?page=%d&limit=300&brand=5786&dest=-1257786&sort=pricedown"
type Response struct {
Data struct {
Products []Product `json:"products"`
} `json:"data"`
}
type Product struct {
ID     int     `json:"id"`
Name   string  `json:"name"`
Price  int     `json:"priceU"`
Rating float32 `json:"reviewRating"`
Sale   int     `json:"sale"`
New    bool    `json:"isNew"`
}
func main() {
var allProducts []Product
for i := 1; ; i++ {
page, err := fetchPage(i)
if err != nil {
log.Fatal(err) // TODO
}
allProducts = append(allProducts, page...)
if len(page) == 0 {
break
}
}
fmt.Println(allProducts)
fmt.Println(len(allProducts))
}
func fetchPage(i int) ([]Product, error) {
resp, err := http.Get(fmt.Sprintf(URL, i))
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, errors.New(resp.Status)
}
var response Response
err = json.NewDecoder(resp.Body).Decode(&response)
if err != nil {
return nil, err
}
return response.Data.Products, nil
}

答案2

得分: 0

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

const URL = "https://catalog.wb.ru/brands/m/catalog?page=%d&limit=300&brand=5786&dest=-1257786&sort=pricedown"

type Response struct {
	Data struct {
		Products []Product `json:"products"`
	} `json:"data"`
}

type Product struct {
	ID     int     `json:"id"`
	Name   string  `json:"name"`
	Price  int     `json:"priceU"`
	Rating float32 `json:"reviewRating"`
	Sale   int     `json:"sale"`
	New    bool    `json:"isNew"`
}

func main() {
	var products = []Product{}

	for i := 1; ; i++ {
		resp, err := http.Get(fmt.Sprintf(URL, i))
		if err != nil {
			fmt.Printf("#1 Error: %s", err)
		}
		defer resp.Body.Close()

		bytes, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			fmt.Printf("#2 Error: %s", err)
		}

		// 将响应解析为 Response 结构体
		var response Response
		err = json.Unmarshal(bytes, &response)
		if err != nil {
			fmt.Printf("#3 Error: %s", err)
			break
		}

		fmt.Printf("\n第 %d 页的切片\n字节长度:%d\n", i, len(bytes))
		fmt.Printf("finalResult 的长度:%d\n", len(response.Data.Products))

		if len(response.Data.Products) == 0 {
			fmt.Println("没有更多数据")
			break
		}

		// 如果有产品,则将其追加到 products 切片中
		products = append(products, response.Data.Products...)
	}

	fmt.Println("products:", products)
	fmt.Println("产品总数:", len(products))
}
英文:

Instead of unmarshaling the reponse with []byte, we can unmarshal it with the Response struct.

Here is the updated code

package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
const URL = "https://catalog.wb.ru/brands/m/catalog?page=%d&limit=300&brand=5786&dest=-1257786&sort=pricedown"
type Response struct {
Data struct {
Products []Product `json:"products"`
} `json:"data"`
}
type Product struct {
ID     int     `json:"id"`
Name   string  `json:"name"`
Price  int     `json:"priceU"`
Rating float32 `json:"reviewRating"`
Sale   int     `json:"sale"`
New    bool    `json:"isNew"`
}
func main() {
var products = []Product{}
for i := 1; ; i++ {
resp, err := http.Get(fmt.Sprintf(URL, i))
if err != nil {
fmt.Printf("#1 Error: %s", err)
}
defer resp.Body.Close()
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("#2 Error: %s", err)
}
// The response has defined as `Response` type and unmarshaling
var response Response
err = json.Unmarshal(bytes, &response)
if err != nil {
fmt.Printf("#3 Error: %s", err)
break
}
fmt.Printf("\nSlice from page #%d\nLength of bytes: %d\n", i, len(bytes))
fmt.Printf("Length of finalResult: %d\n", len(response.Data.Products))
if len(response.Data.Products) == 0 {
fmt.Println("There's no more data")
break
}
// if there has products then append into the Products slice
products = append(products, response.Data.Products...)
}
fmt.Println("products:", products)
fmt.Println("Total products count:", len(products))
}

huangapple
  • 本文由 发表于 2023年6月19日 18:15:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76505649.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定