Here Is my json file and i want to insert the data using golang and
mgo in this json format
[{
"_id" : ObjectId("57307906f051147d5317984e"),
"dateAdded" : " 20015-11-10 23:00:00 +0000 UTC"
"firstName" : "chetan",
"lastName" : "kumar",
"age" : 23,
"user" : [
{
"userid" : ObjectId("57307906f051147d5317984a"),
"firstName" : "chetan",
"lastName" : "kumar",
"age" : 23
},
{
"userid" : ObjectId("57307906f051147d5317984b"),
"firstName" : "nepolean",
"lastName" : "dang",
"age" : 26
},
{
"userid" : ObjectId("57307906f051147d5317984c"),
"firstName" : "Raj",
"lastname" : "kumar",
"age" : 26
}
],
"sales" : [
{
"salesid" : ObjectId("57307906f051147d5317984d"),
"firstName" : "ashu",
"lastName" : "jha",
"age" : 27
}
]
}]
Now ,here is my go file which i was trying to insert data through
golang and mgo
package main
import(
"fmt"
"time"
"net/http"
"github.com/gorilla/mux"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
type userinfo struct{
ID bson.ObjectId `json:"_id" bson:"_id"`
USER []User `json:"user" bson:"user"`
SALES []Sales `json:"sales" bson:"sales"`
DATEADDED time.Time `json:"dateAdded" bson:"dateAdded"`
NAME string `json:"name" bson:"name"`
}
type User struct{
USERID bson.ObjectId `json:"userid" bson:"userid"`
FIRSTNAME string `json:"firstName" bson:"firstName"`
LASTNAME string `json:"lastName" bson:"lastName"`
AGE int `json:"age" bson:"age"`
}
type Sales struct{
SALESID bson.ObjectId `json:"salesid" bson:"salesid"`
FIRSTNAME string `json:"firstName" bson:"firstName"`
LASTNAME string `json:"lastName" bson:"lastName"`
AGE int `json:"age" bson:"age"`
}
func post(w http.ResponseWriter,r *http.Request){
session,err := mgo.Dial("127.0.0.1")
if err != nil{
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic,true)
c:= session.DB("userdb").C("user")
fmt.Fprintln(w,"conn")
err = c.Insert(&userinfo{ID:new ObjectId(),NAME:"Admin",USER:{USERID:new ObjectId(), FIRSTNAME: "sam",LASTNAME : "billing",AGE : 25},SALES:{SALESID:new ObjectId(),FIRSTNAME : "joe",LASTNAME : "root",AGE : 23},DATEADDED:time.Now()})
if err != nil {
panic(err)
}
}
func main(){
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/post/",post)
http.ListenAndServe(":8080",router)
}
but it's not work at all please help me out
There is so much wrong with this.
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"time"
"github.com/gorilla/mux"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
type Userinfo struct {
ID bson.ObjectId `bson:"_id,omitempty" json:"id"`
USER []string `json:"user" bson:"user"`
SALES []string `json:"sales" bson:"sales"`
DATEADDED time.Time `json:"dateAdded" bson:"dateAdded"`
NAME string `json:"name" bson:"name"`
}
type User struct {
ID bson.ObjectId `bson:"_id,omitempty" json:"id"`
FIRSTNAME string `json:"firstName" bson:"firstName"`
LASTNAME string `json:"lastName" bson:"lastName"`
AGE int `json:"age" bson:"age"`
}
type Sales struct {
ID bson.ObjectId `bson:"_id,omitempty" json:"id"`
FIRSTNAME string `json:"firstName" bson:"firstName"`
LASTNAME string `json:"lastName" bson:"lastName"`
AGE int `json:"age" bson:"age"`
}
var session *mgo.Session
func main() {
var err error
session, err = mgo.Dial("127.0.0.1")
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
fmt.Fprintln(w, "conn")
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/post/", post)
router.HandleFunc("/getusers/", getusers)
http.ListenAndServe(":8080", router)
}
func post(w http.ResponseWriter, r *http.Request) {
ms := session.Copy()
defer ms.Close()
cui := session.DB("userdb").C("userinfo")
cu := session.DB("userdb").C("user")
cs := session.DB("userdb").C("sales")
u := User{FIRSTNAME: "sam", LASTNAME: "billing", AGE: 25}
s := Sales{FIRSTNAME: "joe", LASTNAME: "root", AGE: 23}
if e := cu.Insert(u); e != nil {
log.Println(e.Error)
w.WriteHeader(500)
return
}
if e := cs.Insert(s); e != nil {
log.Println(e.Error)
w.WriteHeader(500)
return
}
ui := new(Userinfo)
ui.ID = bson.NewObjectId()
ui.NAME = "admin"
ui.USER = []string{u.Id.Hex()}
ui.SALES = []string{s.Id.Hex()}
ui.DATEADDED = time.Now()
if e := cui.Insert(ui); e != nil {
log.Println(e.Error)
w.WriteHeader(500)
return
}
w.WriteHeader(201)
}
func getusers(w http.ResponseWriter, r *http.Request) {
ms := session.Copy()
defer ms.Close()
cui := session.DB("userdb").C("userinfo")
cu := session.DB("userdb").C("user")
cs := session.DB("userdb").C("sales")
// Query for users of userinfo
uadm := new(Userinfo)
if e := cui.Find(bson.M{"name": "admin"}).One(uadm); e != nil {
log.Println(e.Error)
}
for _, userid := range uadm.USER {
tempu := new(User)
if e := cu.Find(bson.M{"_id": bson.ObjectIdHex(userid)}).One(tempu); e != nil {
log.Println(e.Error)
w.WriteHeader(500)
return
}
enc := json.NewEncoder(w)
if e := enc.Encode(tempu); e != nil {
log.Println(e.Error)
w.WriteHeader(500)
return
}
}
}
The session
Separate collections for all models
I've changed the user and sales fields of Userinfo into []string because every independantly editable and queryable model should have its own collection. Instead of the whole object the id reference is saved so you can query for a user by ObjectId.
Userinfo should be uppercase
Your syntax is off, in several places. However the code is messy so I'll split it like that:
users := {USERID: new ObjectId(), FIRSTNAME: "sam",LASTNAME: "billing", AGE: 25}
sales := {SALESID: new ObjectId(),FIRSTNAME: "joe", LASTNAME: "root", AGE: 23}
info := &userinfo{ID:new ObjectId(), NAME:"Admin", USER: users, SALES: sales, DATEADDED: time.Now()}
About the creation of sales and user, this is not the right way to create a slice and a struct. Instantiation of a struct of type T in Golang is T{}. You can create slices the same way. Therefore the sales and users become
users := []User{User{USERID: new ObjectId(), FIRSTNAME: "sam",LASTNAME: "billing", AGE: 25}}
sales := []Sales{Sales{SALESID: new ObjectId(),FIRSTNAME: "joe", LASTNAME: "root", AGE: 23}}
Then, you should take a look at mgo's documentation. The way of creating an ObjectId is bson.NewObjectId(). Now, with all the modifications:
func main() {
users := []User{User{USERID: bson.NewObjectId(), FIRSTNAME: "sam", LASTNAME: "billing", AGE: 25}}
sales := []Sales{Sales{SALESID: bson.NewObjectId(), FIRSTNAME: "joe", LASTNAME: "root", AGE: 23}}
info := &userinfo{ID: bson.NewObjectId(), NAME: "Admin", USER: users, SALES: sales, DATEADDED: time.Now()}
data, _ := json.MarshalIndent(info, "", " ")
fmt.Println(string(data))
}
/* Prints
{
"_id": "57402f27e13823740d742417",
"user": [
{
"userid": "57402f27e13823740d742415",
"firstName": "sam",
"lastName": "billing",
"age": 25
}
],
"sales": [
{
"salesid": "57402f27e13823740d742416",
"firstName": "joe",
"lastName": "root",
"age": 23
}
],
"dateAdded": "2016-05-21T11:49:27.507636096+02:00",
"name": "Admin"
}
*/
Related
I have an array of objects that I would like to use to create a new slice while grouping a field for objects with the same id(the id, in this case, the id is pay_method_id) into an array of objects. i.e I want to group all users with a particular payment method
sample input
[{
"user_id": 1,
"pay_method_id": 1
}
{
"user_id": 2,
"pay_method_id": 2
}
{
"user_id": 4,
"pay_method_id": 1
}
{
"user_id": 3,
"pay_method_id": 2
}]
expected output
[
{"pay_method_id" : "2",
"users": [{"user_id": 2}, {"user_id": 3}]
}
{
"pay_method_id" : "1",
"users": [{"user_id": 4}, {"user_id": 1}]
}
]
Struct representing input
type paymenthodUsers struct{
PayMethodID int
UserID int
}
Struct for the output
type paymentMethodGrouped struct{
PayMethodID int
Users []user
}
type user struct{
UserID int
}
How do I generate the expected output above in golang?
package main
import (
"encoding/json"
"fmt"
"log"
)
type paymenthodUsers struct {
PayMethodID int `json:"pay_method_id"`
UserID int `json:"user_id"`
}
type paymentMethodGrouped struct {
PayMethodID int `json:"pay_method_id"`
Users []user `json:"users"`
}
type user struct {
UserID int `json:"user_id"`
}
func main() {
_json := `[{
"user_id": 1,
"pay_method_id": 1
},
{
"user_id": 2,
"pay_method_id": 2
},
{
"user_id": 4,
"pay_method_id": 1
},
{
"user_id": 3,
"pay_method_id": 2
}]`
var paymentmethods []paymenthodUsers
err := json.Unmarshal([]byte(_json), &paymentmethods)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Original input : %+v\n", paymentmethods)
groups := make(map[int][]user)
for _, pm := range paymentmethods {
if _, found := groups[pm.PayMethodID]; !found {
groups[pm.PayMethodID] = []user{}
}
groups[pm.PayMethodID] = append(groups[pm.PayMethodID], user{pm.UserID})
}
paymentGroups := []paymentMethodGrouped{}
for k, v := range groups {
paymentGroups = append(paymentGroups, paymentMethodGrouped{k, v})
}
data, err := json.Marshal(paymentGroups)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Grouped: %s", string(data))
}
Go Playground Demo
I am running the below code. When a user saved in db then blank address is saved I have assigned the null struct to address before save. I can not add the omitempty with all the fields for address struct. How I can avoid to save blank address object within users collection
package main
import (
"context"
"fmt"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type User struct {
Id int `json:"id" bson:"_id,omitempty"`
FirstName string `json:"first_name,omitempty" bson:"first_name,omitempty"`
LastName string `json:"last_name,omitempty" bson:"last_name,omitempty"`
FullName string `json:"full_name,omitempty" bson:"full_name,omitempty"`
CompanyName string `json:"company_name" bson:"company_name"`
Address AddressStruct `json:"address,omitempty" bson:"address,omitempty"`
}
type AddressStruct struct {
Address string `json:"address" bson:"address"`
City string `json:"city" bson:"city"`
State string `json:"state" bson:"state"`
Zipcode string `json:"zipcode" bson:"zipcode"`
Apt string `json:"apt" bson:"apt"`
Default bool `json:"default" bson:"default"`
Status int8 `json:"status,omitempty" bson:"status,omitempty"`
Country string `json:"country,omitempty" bson:"country,omitempty"`
ShortAddress string `json:"short_address" bson:"short_address"`
}
func main() {
var user User
user.FirstName = "Swati"
user.LastName = "Sharma"
user.FullName = "Swati Sharma"
user.Address = AddressStruct{}
client, ctx := ConnectDbWithNewDriver()
defer client.Disconnect(ctx)
a, b := DbInsertOne(client, user)
fmt.Println("Section1", a, b)
}
func ConnectDbWithNewDriver() (client *mongo.Client, ctx context.Context) {
ctx = context.Background()
client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://127.0.0.1:27017").SetConnectTimeout(5*time.Second))
if err != nil {
fmt.Println("CreateSession: ", err)
client.Disconnect(ctx)
return
}
return
}
func DbInsertOne(client *mongo.Client, data interface{}) (interface{}, error) {
collection := client.Database("swatitest").Collection("users")
insertResult, err := collection.InsertOne(context.TODO(), data)
if err != nil {
return nil, err
}
return insertResult.InsertedID, nil
}
When I run this code then record saved in db like this:
{
"_id" : ObjectId("61af41b32214b16fe93435a6"),
"first_name" : "Swati",
"last_name" : "Sharma",
"full_name" : "Swati Sharma",
"company_name" : "",
"address" : {
"address" : "",
"city" : "",
"state" : "",
"zipcode" : "",
"apt" : "",
"default" : false,
"short_address" : ""
}
}
I want to save like:
{
"_id" : ObjectId("61af41b32214b16fe93435a6"),
"first_name" : "Swati",
"last_name" : "Sharma",
"full_name" : "Swati Sharma",
"company_name" : ""
}
You may use the omitempty bson tag option, all Go drivers handle it and will not save the field if it's value is the zero value (for primitive types).
So add it to all fields you don't want to get saved as empty string:
type AddressStruct struct {
Address string `json:"address" bson:"address,omitempty"`
City string `json:"city" bson:"city,omitempty"`
State string `json:"state" bson:"state,omitempty"`
Zipcode string `json:"zipcode" bson:"zipcode,omitempty"`
Apt string `json:"apt" bson:"apt,omitempty"`
Default bool `json:"default" bson:"default,omitempty"`
Status int8 `json:"status,omitempty" bson:"status,omitempty"`
Country string `json:"country,omitempty" bson:"country,omitempty"`
ShortAddress string `json:"short_address" bson:"short_address,omitempty"`
}
If you can't modify the struct type, then don't save the struct value. Create your own type (where you add omitempty), copy the struct value into it, and save your own copy.
I'm trying to get some groups from the config, which names are not known (will get more later on).
I'm new to golang and struggling a bit. I'm using Viper, because of its support for yaml, json and toml.
json config:
{
"database": {
"db": "mydb",
"host": "localhost",
"pass": "mypassword",
"port": 3306,
"user": "username"
},
"customers": {
"company_one": {
"address": "66 Great Queen St, London WC2B 5BX, UK",
"contacts": [
{
"email": "joe.doe#company-one.local",
"name": "Joe Doe"
},
{
"email": "jane.doe#company-one.local",
"name": "Jane Doe"
}
]
},
"company_two": {
"address": "Irish Town Pl, Gibraltar GX11 1AA, Gibraltar",
"contacts": [
{
"email": "lucky.luke#second-company.local",
"name": "Lucky Luke"
}
]
}
}
}
and the source:
package main
import (
"fmt"
"log"
"github.com/spf13/viper"
)
type Config struct {
database Database
customers Customer
}
type Database struct {
host string
port uint16
user string
pass string
db string
}
type Customer struct {
company Company
}
type Company struct {
contacts Contact
address string
}
type Contact struct {
name string
email string
}
func main() {
viper.SetConfigName("a")
viper.AddConfigPath(".")
if err := viper.ReadInConfig(); err != nil {
log.Fatal("Unable to read config file", err)
}
var conf Config
database := viper.GetStringMap("database")
for key, i := range database {
switch key {
case "host":
conf.database.host = i.(string)
case "port":
conf.database.port = i.(uint16)
case "user":
conf.database.user = i.(string)
case "pass":
conf.database.pass = i.(string)
case "db":
conf.database.db = i.(string)
}
}
fmt.Printf("%v\n", conf)
}
I have no idea how to cycle through the customers.
I have tried this one already (converted from go-toml to viper), but it didn't work as expected:
var contMap = map[string]Contacts
cust := config.Get("customers")
for _, c := range cust.Keys() {
sub := cust.Get(c).([]interface{})
for _,d := range sub{
address := d.([]interface{})[0].(string)
hostMap[host] = Contacts{
email: email,
name: name,
}
}
log.Printf("Customers: %s contact: %q", c, sub)
}
I started down the road of answering your initial question but it is so cumbersome and probably not what you actually want.
Your code as you've pasted it has a bunch of errors in it so instead let me offer a simpler solution like I was talking about in my comment.
package main
import (
"log"
"github.com/spf13/viper"
)
type Config struct {
Database Database `mapstructure:"database"`
Customers map[string]Company `mapstructure:"customers"`
}
type Database struct {
Host string `mapstructure:"host"`
Port uint16 `mapstructure:"port"`
User string `mapstructure:"user"`
Pass string `mapstructure:"pass"`
Db string `mapstructure:"db"`
}
type Company struct {
Address string `mapstructure:"address"`
Contacts []Contact `mapstructure:"contacts"`
}
type Contact struct {
Name string `mapstructure:"name"`
Email string `mapstructure:"email"`
}
func main() {
viper.SetConfigName("config")
viper.AddConfigPath(".")
if err := viper.ReadInConfig(); err != nil {
log.Fatal("Unable to read config file", err)
}
var conf Config
err := viper.Unmarshal(&conf)
if err != nil {
panic(err)
}
log.Printf("%#v", conf)
}
If you run this code with your JSON config file (named config) it returns the following output:
2018/04/28 14:47:54
main.Config{Database:main.Database{Host:"localhost", Port:0xcea,
User:"username", Pass:"mypassword", Db:"mydb"},
Customers:map[string]main.Company{"company_two":main.Company{Address:"Irish
Town Pl, Gibraltar GX11 1AA, Gibraltar",
Contacts:[]main.Contact{main.Contact{Name:"Lucky Luke",
Email:"lucky.luke#second-company.local"}}},
"company_one":main.Company{Address:"66 Great Queen St, London WC2B
5BX, UK", Contacts:[]main.Contact{main.Contact{Name:"Joe Doe",
Email:"joe.doe#company-one.local"}, main.Contact{Name:"Jane Doe",
Email:"jane.doe#company-one.local"}}}}}
And here it is reformatted as it would be written if you were creating this whole structure in code:
Config{
Database{
Host: "localhost",
Port: 0xcea,
User: "username",
Pass: "mypassword",
Db: "mydb"},
Customers: map[string]Company{
"company_two": Company{Address: "Irish Town Pl, Gibraltar GX11 1AA, Gibraltar",
Contacts: []Contact{
Contact{Name: "Lucky Luke", Email: "lucky.luke#second-company.local"}}},
"company_one": Company{Address: "66 Great Queen St, London WC2B 5BX, UK",
Contacts: []Contact{
Contact{Name: "Joe Doe", Email: "joe.doe#company-one.local"},
Contact{Name: "Jane Doe", Email: "jane.doe#company-one.local"}}},
},
}
Currently, I am learning hyperledger/fabric and trying to write the chaincode. Below is the invoke function and customized function I created.
type Donation struct {
Id string `json:"id"`
Who string `json:"who"`
Rid string `json:"rid"`
Money int `json:"money"`
}
type Request struct {
Id string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
ExpectedMoney int `json:"expectedMoney"`
CurrentMoney int `json:"currentMoney"`
DonationList []string `json:"donationList"`
}
type Person struct {
Id string `json:"id"`
Name string `json:"name"`
MyRequests []string `json:"myRequests"`
MyDonations []string `json:"myDonations"`
}
func (t *SimpleChaincode) Invoke(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
if function == "createDonation" {
return t.createDonation(stub, args)
}
return nil, errors.New("Received unknown function invocation")
}
func (t *SimpleChaincode) createDonation(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
var from, toRid string
var money int
var err error
if len(args) != 3 {
return nil, errors.New("My createDonation. Incorrect number of arguments. Expecting 3")
}
from = args[0]
toRid = args[1]
money, err = strconv.Atoi(args[2])
if err != nil {
return nil, errors.New("money cannot convert to number")
}
var donation Donation
donation = Donation{Id: "donationid", Rid: toRid, Who: from, Money: money}
djson, err := json.Marshal(&donation)
if err != nil {
return nil, err
}
var a = donation.Id
stub.PutState(a, djson)
personByte, err := stub.GetState(from + "")
fmt.Println(personByte)
return nil, nil
}
func (t *SimpleChaincode) read(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
log.Println("Get into read function")
var key, jsonResp string
var err error
key = args[0]
valAsbytes, err := stub.GetState(key)
if err != nil {
jsonResp = "{\"Error\":\"Failed to get state for " + key + "\"}"
return nil, errors.New(jsonResp)
}
if valAsbytes == nil {
return []byte("cannot find the key's value of the chaincode"), nil
}
return valAsbytes, nil
}
However, When I tried to use swagger UI to invoke and retrieve the "donationid"'s value, it is empty. Is there anything wrong about my code? Thanks in advance.
Invoke
{
"jsonrpc": "2.0",
"method": "invoke",
"params": {
"type": 1,
"chaincodeID": {
"name": "92d975f9301f9b72c7b148e65dcc835a971be55b2555a45c41d6d2eed04ecfd6b1974245cfb77d002e244e9e581e4042747e9f4d6a46b59e9d7e8a7419476296"
},
"ctorMsg": {
"function": "createDonation",
"args": [
"Simon",
"requestid",
"300"
]
},
"secureContext": "user_type1_XXXXXXX"
},
"id": 3
}
query
{
"jsonrpc": "2.0",
"method": "query",
"params": {
"type": 1,
"chaincodeID": {
"name": "92d975f9301f9b72c7b148e65dcc835a971be55b2555a45c41d6d2eed04ecfd6b1974245cfb77d002e244e9e581e4042747e9f4d6a46b59e9d7e8a7419476296"
},
"ctorMsg": {
"function": "read",
"args": [
"donationid"
]
},
"secureContext": "user_type1_xxxxxx"
},
"id": 2
}
I have a collection of documents that were inserted into Mongo looking something like this:
type Stats struct {
UserStatus string `json:"userStatus" bson:"userStatus"`
... a bunch more fields
}
type User struct {
ID bson.ObjectId `json:"-" bson:"_id"`
LastName string `json:"lastName" bson:"lastName"`
FirstName string `json:"firstName" bson:"firstName"`
Role string `json:"role" bson:"role"`
Tags []string `json:"tags" bson:"tags"`
... (a bunch more fields)
Stats UserStats `json:"stats" bson:"stats"`
}
I want to query it to get a specific report, so I tried this:
func UserNameReport() {
... get mongo session, etc.
// create struct of just the data I want returned
type UserNames struct {
LastName string `json:"lastName" bson:"lastName"`
FirstName string `json:"firstName" bson:"firstName"`
... etc
UserStats Stats `json:"stats" bson:"stats"`
}
projection := bson.M{"lastName":1, "firstName":1, etc}
result := []UserNames{}
err := x.Find({query user collection}).Select(projection).All(&result)
...
}
This works - my question is, how can I include just ONE field from the 'Stats' struct? In other words,
I essentially want the "projection" to be this:
projection := bson.M{"lastName":1, ..., "stats.userStatus":1} <-- stats.userStatus doesn't work
...
err := x.Find({query user collection}).Select(projection).All(&result)
I get the entire "Stats" embedded struct in the results - how can I filter out just one field from the sub-document in and put it into the result set?
Thanks!
It works perfectly for me, with MongoDB 2.6.5
The following code:
package main
import (
"fmt"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"log"
)
type Statistics struct {
Url string
Hits int
}
type Person struct {
Num int
Uuid string
Name string
Stats []Statistics
}
func main() {
// Connect to the database
session, err := mgo.Dial("localhost")
if err != nil {
panic(err)
}
defer session.Close()
// Remove people collection if any
c := session.DB("test").C("people")
c.DropCollection()
// Add some data
err = c.Insert(
&Person{1, "UUID1", "Joe", []Statistics{Statistics{"a", 1}, Statistics{"b", 2}}},
&Person{2, "UUID2", "Jane", []Statistics{Statistics{"c", 3}, Statistics{"d", 4}}},
&Person{3, "UUID3", "Didier", []Statistics{Statistics{"e", 5}, Statistics{"f", 6}}})
if err != nil {
log.Fatal(err)
}
result := []Person{}
err = c.Find(bson.M{"$or": []bson.M{bson.M{"uuid": "UUID3"}, bson.M{"name": "Joe"}}}).Select(bson.M{"num": 1, "name": 1, "stats.hits": 1}).All(&result)
if err != nil {
log.Fatal(err)
}
fmt.Println(result)
}
results in:
[{1 Joe [{ 1} { 2}]} {3 Didier [{ 5} { 6}]}]
... which is precisely what I would expect.
Maybe this will help others - essentially I was trying to take a document with an embedded document and return a result set like I would do in SQL with a select a.LastName + ', ' + a.FirstName as Name, b.OtherData and in essence have a different 'table' / 'document'.
So here is my current solution - love to get better ones (more performant?) though!
I created a new struct and I'm using the 'mapstructure' library
import "github.com/goinggo/mapstructure"
type Stats struct {
UserStatus string `json:"userStatus" bson:"userStatus"`
... a bunch more fields
}
type User struct {
ID bson.ObjectId `json:"-" bson:"_id"`
LastName string `json:"lastName" bson:"lastName"`
FirstName string `json:"firstName" bson:"firstName"`
Role string `json:"role" bson:"role"`
Tags []string `json:"tags" bson:"tags"`
... (a bunch more fields)
Stats UserStats `json:"stats" bson:"stats"`
}
type MyReportItem struct {
FirstName string `json:"firstName" jpath:"firstName"`
LastName string `json:"lastName" jpath:"lastName"`
Status string `json:"status" jpath:"stats.userStatus"`
}
type MyReport struct {
Results []MyReportItem `json:"results"`
}
func xxxx(w http.ResponseWriter, r *http.Request) {
var users MyReportItem
// the results will come back as a slice of map[string]interface{}
mgoResult := []map[string]interface{}{}
// execute the query
err := c.Find(finder).Select(projection).All(&mgoResult)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
user := MyReportItem{}
// iterate through the results and decode them into the MyReport struct
for _, x := range mgoResult {
docScript, _ := json.Marshal(x)
docMap := map[string]interface{}{}
json.Unmarshal(docScript, &docMap)
err := mapstructure.DecodePath(docMap, &user)
if err == nil {
users.Results = append(users.Results, user)
}
}
... send back the results ...
_ := json.NewEncoder(w).Encode(&users)
}
Now I get a slice of objects in the form:
results: [
{
firstName: "John",
lastName: "Doe",
status: "active"
}
...
]
Instead of:
{
firstName: "John",
lastName: "Doe",
stats: {
status: "active"
}
}