IBM / cloudant-go-sdk

Cloudant SDK for Go
Apache License 2.0
21 stars 12 forks source link

How to insert and query data from cloudant db in the form of struct? #304

Closed ghost closed 2 years ago

ghost commented 2 years ago

I am using cloudant db in Golang application. And i want to insert the fetch data in the form of struct like... type SessionRequest struct { Type string json:"type" LoginId string json:"loginId" SessionId string json:"sessionId" LoggedInTime time.Time json:"loggedInTime" ExpiryTime time.Time json:"expiryTime" }

And once my data stored in db then i want to query data in the same manner (struct form).

For example i am using below query to fetch records : selector = {"$and": [{"loginId": { "$eq": " + loginId + "}},{"sessionId": { "$eq":" + sessionId + "}}]}

And one more thing i need "ExpiryTime" and "LoggedInTime" in time.Time data type which we have in struct so that we can check the time is expired or not.

Please help me on the same. Thanks in advanced!

emlaver commented 2 years ago

Hello @munesh005 you can convert custom struct -> bytes -> reader and pass that to postBulkDocs to insert your struct as a document. Here's an example:

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "time"

    "github.com/IBM/cloudant-go-sdk/cloudantv1"
)

type SessionRequest struct {
    Type string `json:"type"`
    LoginId string `json:"loginId"`
    SessionId string `json:"sessionId"`
    LoggedInTime time.Time `json:"loggedInTime"`
    ExpiryTime time.Time `json:"expiryTime"`
}

func main() {
    service, _ := cloudantv1.NewCloudantV1UsingExternalConfig(
        &cloudantv1.CloudantV1Options{},
    )
    sRequest := SessionRequest{
        Type: "test",
    }

    requestByte, _ := json.Marshal(map[string]interface{}{"docs": []SessionRequest{sRequest}})
    requestReader := bytes.NewReader(requestByte)
    stringReadCloser := io.NopCloser(requestReader)

    postBulkDocs := service.NewPostBulkDocsOptions(
        "testdb",
    )
    postBulkDocs.SetBody(stringReadCloser)

    bulkDocsResults, _, err := service.PostBulkDocs(postBulkDocs)
    if err != nil {
        panic(err)
      }

    b, _ := json.MarshalIndent(bulkDocsResults, "", "  ")
    fmt.Println(string(b))
}

I used the code above to create the document and here's the output when I fetched it using curl:

{"_id":"341492e8314eb8db967d1d9d8b631a63","_rev":"1-6e57bcfdfc7f583272cad1dcdb6793dd","type":"test","loginId":"","sessionId":"","loggedInTime":"0001-01-01T00:00:00Z","expiryTime":"0001-01-01T00:00:00Z"}

And one more thing i need "ExpiryTime" and "LoggedInTime" in time.Time data type which we have in struct so that we can check the time is expired or not.

I believe this stackoverflow thread for wrapping time.Time as your own custom type should help: https://stackoverflow.com/questions/23695479/how-to-format-timestamp-in-outgoing-json

ricellis commented 2 years ago

you can convert custom struct -> bytes -> reader and pass that to postBulkDocs to insert your struct as a document.

I don't think you have to use PostBulkDocs if you only have a single doc, both PostDocument and PutDocument accept io.ReadCloser bodies.

ghost commented 2 years ago

Hi Rich, Thanks for your reply. When i am using below code as you suggested ...getting error: "bad_contenttype" requestByte, := json.Marshal(map[string]interface{}{"docs": []entities.SessionAuthRequest{createSessionReq}}) requestReader := bytes.NewReader(requestByte) stringReadCloser := io.NopCloser(requestReader) createDocumentOptions := dbClient.NewPostDocumentOptions( dbName, ) createDocumentOptions.SetBody(stringReadCloser) createDocumentResponse, _, err := dbClient.PostDocument(createDocumentOptions) fmt.Println("**err***", err)

And same code is working fine when i am using code below: postBulkDocs := dbClient.NewPostBulkDocsOptions( dbName, ) postBulkDocs.SetBody(stringReadCloser)

bulkDocsResults, _, err := dbClient.PostBulkDocs(postBulkDocs)
ricellis commented 2 years ago

When i am using below code

Well firstly, the JSON body for PostBulkDocs expects a docs array, so while you can use a io.ReadCloser with PostDocument you shouldn't use @emlaver's example verbatim with PostDocument because in that case you need only need the serialized bytes of a single doc, not an array of docs. Otherwise you'll end up with a doc like {"_id": "someuuid", "docs": [{"type":"sometype", ...}]} instead of {"_id": "someuuid", "type": "sometype", ...}

getting error: "bad_content_type"

It should work if you explicitly SetContentType to "application/json".