I am trying to query using bison all JSON data in MongoDB with two fields but am getting null as result.
{
"allowedList": [
{
"List": [
{
"allow": {
"ss": 1,
},
"Information": [
{
"Id": "Id1"
}
]
}
]
}
]
}
I was able to filter all using the MongoDB at command line using
db.slicedb.find({"allowedList.List.allow.ss":1,"allowedList.List.Information.nsiId":"Id-Id21"})
but using
query := bson.M{"allowedList.List.allow": bson.M{"ss": sst}, "allowedList.List.Information": bson.M{"Id": Id}}
sst and Id are integer and string input to the query function
err := db.C(COLLECTION).Find(query).All(&specificSlices)
but is not working, am getting null even though there are json data that match the two field. Can someone help point out what was wrong with my query?
Server and database config
type SliceDataAccess struct {
Server string
Database string
}
var db *mgo.Database
const (
COLLECTION = "slicedb"
)
Establish a connection to database
func (m *SliceDataAccess) Connect() {
session, err := mgo.DialWithTimeout(m.Server, 20*time.Second)
if err != nil {
log.Fatal(err)
}
db = session.DB(m.Database)
}
Structs fields
type InstanceInfo struct {
ID string `json:"nfId" bson:"_id"`
AllowedList []AllowedNssai `json:"allowedList" bson:"allowedList"`
}
type AllowedNssai struct {
List []AllowedSnssai `json:"List,omitempty" bson:"List"`
...
}
type AllowedSnssai struct {
Allow *Snssai `json:"allow,omitempty" bson:"allow"`
Information []NsiInformation `json:"Information,omitempty" bson:"Information"`
}
type NsiInformation struct {
Id string `json:"Id" bson:"Id"`
}
type Snssai struct {
Ss int32 `json:"sst" bson:"ss"`
}
Query function defined
func (m *SliceDataAccess) FindAll(sst int32, nsiId string ([]InstanceInfo, error) {
var specificSlices []InstanceInfo
query := bson.M{"allowedList.List.allow": bson.M{"ss": sst}, "allowedList.List.Information": bson.M{"Id": nsiId}}
err := db.C(COLLECTION).Find(query).All(&specificSlices)
if err != nil {
return specificSlices, err
}
return specificSlices, nil
}
HTTP handler function for request and response
func AvailabilityGet(w http.ResponseWriter, r *http.Request)
var slice InstanceInfo
err := json.NewDecoder(r.Body).Decode(&slice)
if err != nil {
respondWithError(w, http.StatusBadRequest, "Object body not well decoded")
return
}
sst := slice.AllowedList[0].List[0].Allow.Sst
nsiId := slice.AllowedList[0].List[0].Information[0].Id
specificSlices, err := da.FindAll(sst, nsiId)
json.NewEncoder(w).Encode(specificSlices)
}
Attached is my the full go code i have done.
this worked
query := bson.M{"allowedNssaiList.allowedSnssaiList.allowedSnssai.sst": sst, "allowedNssaiList.allowedSnssaiList.nsiInformationList.nsiId": nsiId}
Related
For example, I have this structure:
type Overview struct {
Symbol string `json:"Symbol,omitempty"`
AssetType string `json:"AssetType,omitempty"`
Name string `json:"Name,omitempty"`
Description string `json:"Description,omitempty"`
...
...
}
In addition to this, I have several other structures.
My function selects a suitable structure for Decode(), but when I try to get data from the database, I get the result in this form:
[
{
"Key": "_id",
"Value": "618aa6f2a64cb8105a9c7984"
},
{
"Key": "Symbol",
"Value": "IBM"
},
{
"Key": "FiscalYearEnd",
"Value": "December"
},
...
...
]
I expect a response in the form of my structure, but I get such an array. I tried declaring the structure for the response myself: var result models.Overview. After that, the problem disappeared, but this is not the solution for my problem
There is my function:
var (
models map[string]interface{}
)
func init() {
models = make(map[string]interface{})
models["Overview"] = models.Overview{}
models["Earnings"] = models.Earnings{}
...
...
}
func GetDbData(collection string, db *mongo.Database, filter bson.D) (interface{}, error) {
var result = models[collection] // Choosing a structure
res := db.Collection(collection).FindOne(context.TODO(), filter)
err := res.Decode(&result)
if err != nil {
return nil, err
}
return result, nil
}
I can't understand why this is happening, I hope that someone has already encountered this problem and will be able to help me
https://jira.mongodb.org/browse/GODRIVER-988
Another approach to solve this can be by first decoding it into bson.M type and then unmarshalling it to your struct. Yes, this is not optimal.
eg:
func GetMonthStatusByID(ctx context.Context, id string) (interface{}, error) {
var monthStatus interface{}
filter := bson.M\{"_id": id}
err := db.Collection("Months").FindOne(ctx, filter).Decode(&monthStatus)
return monthStatus, err
}
The above snippet should be changed to:
func GetMonthStatusByID(ctx context.Context, id string) (interface{}, error) {
var monthStatus interface{}
filter := bson.M\{"_id": id}
tempResult := bson.M{}
err := db.Collection("Months").FindOne(ctx, filter).Decode(&tempResult)
if err == nil {
obj, _ := json.Marshal(tempResult)
err= json.Unmarshal(obj, &monthStatus)
}
return monthStatus, err
}
While querying the below data, returned cursor is empty. while there is 100s of documents which satisfy the condition.
{
"_id": "5dd68c51a39809125944ffba",
"status": "success",
"balance": "0.000",
"request_params": {
"username": "test_user",
"service_code": "MR"
}
using below code
MongoDB driver "go.mongodb.org/mongo-driver/mongo"
func saveLog(data Log) bool {
mongo, err := openMongo()
if err != nil {
log.Println(err)
fmt.Println("Connection failed")
return false
} else {
LogCollection := mongo.Database(LogDb).Collection(CollectionLog)
insertedApi, err := LogCollection.InsertOne(context.TODO(), data)
if err != nil {
log.Println(err)
fmt.Println("Insert failed")
return false
} else {
log.Println(insertedApi.InsertedID)
return true
}
}
}
func parseLog() {
db, err := openMongo()
if err != nil {
fmt.Println(err)
fmt.Println("Connection failed")
return
} else {
logCollection := db.Database(LogDb).Collection(CollectionLog)
var results [] *Log
find := bson.D{{"status","success"},{"request_params",bson.D{{"username","test_user"}}}}
fmt.Println(find)
cur, err := logCollection.Find(context.TODO(), find)
if err != nil {
log.Fatal(err)
}else {
for cur.Next(context.TODO()) {
var elem Log
err := cur.Decode(&elem)
if err != nil {
fmt.Println("Parse error : ",err)
}
fmt.Println("Log : ",elem)
results = append(results, &elem)
}
}
}
}
Log write
saveLog(Log{"success","0.000",RequestParams{"test_user","MR"}})
Log read
parseLog()
Log struct
type Log struct {
Status string `bson:"status"`
Balance string `bson:"balance"`
RequestParams RequestParams `bson:"request_params"`
}
type RequestParams struct {
Username string `bson:"username"`
ServiceCode string `bson:"service_code"`
}
MongoDB data
status only is returning whole 8k documents
bson.D{{"status","success"}}
Isn't collection.Find() function the right one for it.
Shell command is returning documents correctly
db.log.find({"status":"success","request_params.username":"test_user"}).limit(10).pretty()
The issue here is because of the query filter. There is a difference between the following queries:
// Query A: {"status": "success", "request_params": {"username":"test_user"}}
find := bson.D{{"status","success"},{"request_params",bson.D{{"username","test_user"}}}}
// Query B: {"status": "success", "request_params.username":"test_user"}
find := bson.D{{"status","success"},{"request_params.username","test_user"}}
Query A means that you would like to match an exact document of request_params where the value object exactly equal to {"username":"test_user"}. None of the documents in your collection matches this criteria. The documents also contains {"service_code":"MR"}. While query B uses dot notation, which means that you would like to match request_params field where it contains a value of {"username":"test_user"}.
See also Query on Nested Field for more information.
I have this data in my mongoDB database.
{
"_id":"5d9ce9fd270eae22adb95d70",
...
"isdriver":true,
"driver":{
"walletmoney":0,
"license":"6eef8271-62d7-4a1c-972a-2c40a773b35a",
"vehicle":{
"image":"b6c3619b-86e6-49d0-8734-e2c48815dfc1",
"insurance":"5f8229c4-4700-4059-8b72-9344a2bc6092",
"manufacturer":"Tesla",
"model":"Model 3",
"vin":"12345678912345678",
"year":2018
},
"verified":false
...
}
}
Here is my driver struct
type Driver struct {
...
Verified bool `json:"verified,omitempty"`
License string `json:"licenseimage,omitempty"`
...
Vehicle Vehicle `json:"vehicle,omitempty"`
}
Here is my Student Struct
type Student struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
...
IsDriver bool `json:"isdriver,omitempty"`
Driver Driver `json:"driver,omitempty"`
}
Vehicle struct
type Vehicle struct {
Image string `json:"vehicleimage,omitempty"`
Insurance string `json:"insuranceimage,omitempty"`
VIN string `json:"vin,omitempty"`
Manufacturer string `json:"manufacturer,omitemptyr"` <-----(Edit) Find out this is also wrong
Model string `json:"model,omitempty"`
Year uint16 `json:"year,omitempty"`
}
And I'm using this function to get all the drivers from the database
func GetAllDrivers() []model.Driver {
// Options
projections := bson.D{
{"driver", 1},
/* {"driver.verified", 1},
{"driver.license", 1}, */
}
// Filter for search
filter := bson.M{"isdriver": true}
// Return student collection (*mongo.Collection)
studentCollection := GetStudentCollection()
cur, err := studentCollection.Find(context.TODO(), filter, options.Find().SetProjection(projections))
// Error while finding documents
if err != nil {
fmt.Print(err)
return []model.Driver{}
}
var drivers []model.Driver
var driver model.Driver
// Get the next result from the cursor
for cur.Next(context.TODO()) {
err := cur.Decode(&driver)
if err != nil {
fmt.Print(err)
}
drivers = append(drivers, driver)
}
if err := cur.Err(); err != nil {
fmt.Print(err)
}
cur.Close(context.TODO())
return drivers
}
But the response I'm getting in the postman is ridiculous
[
{
"vehicle": {
"manufacturer": ""
}
},
{
"vehicle": {
"manufacturer": ""
}
}
]
One thing is okay that is in response I'm getting two objects which are fine because as my filter suggestest isdriver: true I have total three documents in the database in which two of those have isdriver: true.
Can anybody help me with this? Why I'm getting this response?
You are doing a find in the students collection, but you decode into a driver.
This needs to be changed.
var drivers []Driver
var student Student
// Get the next result from the cursor
for cur.Next(context.TODO()) {
err := cur.Decode(&student)
if err != nil {
fmt.Println(err)
}
drivers = append(drivers, student.Driver)
}
Furthermore , you are lacking an Inline struct tag for the Driver field of Student:
type Student struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
IsDriver bool `json:"isdriver,omitempty"`
// Note that Inline is uppercase.
Driver Driver `json:"driver,omitempty" bson:"driver,Inline"`
}
Same, of course, goes for all referenced structs. Working sample code: https://gist.github.com/mwmahlberg/c46ec3ad3ccee028f0666ff7d5d8d98b
How do i query polls by id with go-gin and MongoDB, i have tried several methods but i still get errors (not found), can't seem to find a walk around below is my code, with my database on mongoDB:
type Poll struct {
//ID string `json:"_id,omitempty"`
ID bson.ObjectId `json:"id,omitempty" bson:"_id,omitempty"`
Firstname string `json:"firstname,omitempty"`
Lastname string `json:"lastname,omitempty"`
Poll string `json:"poll,omitempty"`
// Address *Address `json:"address,omitempty"`
}
var (
// Session stores mongo session
Session *mgo.Session
// Mongo stores the mongodb connection string information
Mongo *mgo.DialInfo
)
const (
// MongoDBUrl is the default mongodb url that will be used to connect to the
// database.
MongoDBUrl = "mongodb://localhost:27017/smartpoll"
// CollectionPoll holds the name of the poll collection
CollectionPoll = "polls"
)
// Connect connects to mongodb
func Connect() {
uri := os.Getenv("MONGODB_URL")
if len(uri) == 0 {
uri = MongoDBUrl
}
mongo, err := mgo.ParseURL(uri)
s, err := mgo.Dial(uri)
if err != nil {
fmt.Printf("Can't connect to mongo, go error %v\n", err)
panic(err.Error())
}
s.SetSafe(&mgo.Safe{})
fmt.Println("Connected to", uri)
Session = s
Mongo = mongo
}
func init() {
Connect()
}
func main() {
port := os.Getenv("PORT")
if port == "" {
log.Fatal("$PORT must be set")
}
router := gin.Default()
router.Use(ConnectMiddleware)
router.GET("/", func (c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "OK"})
})
router.GET("/polls/:_id", pollsByID)
router.Run(":" + port)
}
func ConnectMiddleware(c * gin.Context) {
c.Set("db", Session.DB(Mongo.Database))
c.Next()
}
func pollsByID(c * gin.Context) {
db := c.MustGet("db").(*mgo.Database)
id := c.Param("id")
poll := []Poll{}
// err := db.C(CollectionPoll).Find(id).One(&poll)
err := db.C(CollectionPoll).Find(bson.M{"_id": id}).One(&poll)
if err != nil {
//c.Error(err)
//panic(err)
log.Println(err)
}
result := gin.H{"payload": poll}
c.Writer.Header().Set("Content-Type", "application/json")
c.JSON(200, result)
}
my DB is as follows:
{
"_id" : ObjectId("58d9cf1cdf353f3d2f5951b4"),
"id" : "1",
"firstname" : "Sam",
"lastname" : "Smith",
"poll" : "Who is the Richest in the World"
}
Your ID is an ObjectId, but your input is a string. You need to use bson.ObjectIdHex to parse the string into an ObjectId:
err := db.C(CollectionPoll).FindId(bson.ObjectIdHex(id)).One(&poll)
Change polls from an array:
polls := []Poll{}
TO:
polls := Poll{}
I'm trying to code a simple web app in Go using Mongodb.
I've created a minimalistic simple Model / Controller setup.
I can create new user using POST with url "/user" with data such as '{"pseudo": "bobby1"}'. The user is created. However, when looking inside Mongodb shell, I get:
{ "_id" : ObjectId("5616d1ea56ca4dbc03bb83bc"), "id" : ObjectId("5616d1ea5213c64824000001"), "pseudo" : "bobby2"}
The "id" field is the one coming from my struct and the "_id" field is the one from Mongodb. From looking at different sample code, it looked like I could use myself the one from Mongodb but I can't find how to do it.. ><
Since the "id" is only used by me, I can't find user by their ID since I do not have that one...
More over, when I do a GET /user, it returns the full list of user, and I only get:
{"id":"5616d1ea5213c64824000001","pseudo":"bobby2"
Not the "real" Mongodb Id...
Thanks,
Here's the code:
model/user.go
const userCollection = "user"
// Get our collection
var C *mgo.Collection = database.GetCollection(userCollection)
// User represents the fields of a user in db
type User struct {
Id bson.ObjectId `json:"id"i bson:"_id,omitempty"`
Pseudo string `json:"pseudo" bson:"pseudo"`
}
// it will return every users in the db
func UserFindAll() []User {
var users []User
err := C.Find(bson.M{}).All(&users)
if err != nil {
panic(err)
}
return users
}
// UserFIndId return the user in the db with
// corresponding ID
func UserFindId(id string) User {
if !bson.IsObjectIdHex(id) {
s := fmt.Sprintf("Id given %s is not valid.", id)
panic(errors.New(s))
}
oid := bson.ObjectIdHex(id)
u := User{}
if err := C.FindId(oid).One(&u); err != nil {
panic(err)
}
return u
}
// UserCreate create a new user on the db
func UserCreate(u *User) {
u.Id = bson.NewObjectId()
err := C.Insert(u)
if err != nil {
panic(err)
}
}
controller/user.go
/ GetAll returns all users
func (us *UserController) GetAll(w http.ResponseWriter, request *http.Request) {
// u := model.User{
// ID: "987654321",
// Pseudo: "nikko",
// }
users := model.UserFindAll()
bu, err := json.Marshal(users)
if err != nil {
fmt.Printf("[-] Error while marshaling user struct : %v\n", err)
w.Write([]byte("Error Marshaling"))
w.WriteHeader(404)
return
}
w.Header().Set("Content-type", "application/json")
w.WriteHeader(200)
fmt.Fprintf(w, "%s\n", bu)
}
// Get return a specific user according to Id
func (us *UserController) Get(w http.ResponseWriter, request *http.Request) {
vars := mux.Vars(request)
ps := vars["id"]
u := model.UserFindId(ps)
bu, err := json.Marshal(u)
if err != nil {
fmt.Printf("[-] Error while marshaling user struct : %v\n", err)
w.Write([]byte("Error Marshaling"))
w.WriteHeader(404)
return
}
w.Header().Set("Content-type", "application/json")
w.WriteHeader(200)
fmt.Fprintf(w, "%s\n", bu)
}
func (us *UserController) Post(w http.ResponseWriter, r *http.Request) {
u := model.User{}
json.NewDecoder(r.Body).Decode(&u)
model.UserCreate(&u)
bu, err := json.Marshal(u)
if err != nil {
fmt.Printf("[-] Error PUT user struct : %v\n", err)
w.WriteHeader(404)
return
}
w.Header().Set("Content-type", "application/json")
w.WriteHeader(201)
fmt.Fprintf(w, "%s\n", bu)
}
Looks like you have a stray character in your struct tags:
type User struct {
Id bson.ObjectId `json:"id"i bson:"_id,omitempty"`
Pseudo string `json:"pseudo" bson:"pseudo"`
}
That i should not exist after json:"id". It should be:
type User struct {
Id bson.ObjectId `json:"id" bson:"_id,omitempty"`
Pseudo string `json:"pseudo" bson:"pseudo"`
}