How query nested array by time range mongodb with golang driver? - mongodb

A have booking system with apoinments and need to get all booking objects with apoinments filtering with special time.
{
"id": "6295001bef176110cb52076c",
"companyID": "6294deeed16a4491020a6f3a",
"createdAt": "2022-05-30T17:34:19.458Z",
"updatedAt": "2022-05-31T12:23:58.805Z",
"apoinments": [
{
"id": "62a349a1fe907103f8d33111",
"startTime": "2022-06-10T12:00:00Z",
"endTime": "2022-06-10T14:00:00Z",
"createdAt": "2022-06-10T13:39:45.057Z",
"companyID": "6294deeed16a4491020a6f3a",
"bookingItemID": "6295001bef176110cb52076c",
},
{
"id": "62a349c0fe907103f8d33112",
"startTime": "2022-06-10T14:00:00Z",
"endTime": "2022-06-10T16:00:00Z",
"createdAt": "2022-06-10T13:40:16.927Z",
"companyID": "6294deeed16a4491020a6f3a",
"bookingItemID": "6295001bef176110cb52076c",
}
],
"title": "One",
}
I need to get all booking objects with their apoinments with startTime and endTime with special range so i do:
func (companyRepository *companyRepositoryImpl) GetCompanyBookingItems(companyID string) (*model.CompanyBookingItems, error) {
var existingCompany model.Company
objectId, _ := primitive.ObjectIDFromHex(companyID)
filter := bson.M{"_id": objectId}
err := companyRepository.Connection.Collection("companies").FindOne(cntx, filter).Decode(&existingCompany)
if err != nil {
return nil, exception.ResourceNotFoundException("Company", "id", companyID)
}
switch hour := time.Now().Hour(); { // missing expression means "true"
// dev
case hour >= 8 && hour <= 23:
// prod
// case hour >= 3 && hour <= 18:
// log.Println("hour", hour)
startDate := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 11, 0, 0, 0, time.UTC)
endDate := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day()+1, 05, 0, 0, 0, time.UTC)
bookingItems := *existingCompany.BookingItems
for i := range bookingItems {
bookingItem := bookingItems[i]
var newApoinments []model.Apoinment
for _, apoinment := range *bookingItem.Apoinments {
if apoinment.StartTime.Local().After(startDate.Local()) && apoinment.EndTime.Local().Before(endDate.Local()) {
newApoinments = append(newApoinments, apoinment)
// log.Println("10 - 23", apoinment.ClientName)
}
}
*bookingItems[i].Apoinments = newApoinments
}
// dev
case hour >= 0 && hour <= 7:
// prod
// case hour >= 19 && hour <= 2:
startDate := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day()-1, 11, 0, 0, 0, time.UTC)
endDate := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 05, 0, 0, 0, time.UTC)
// log.Println("start", startDate)
// log.Println("end", endDate)
bookingItems := *existingCompany.BookingItems
for i := range bookingItems {
bookingItem := bookingItems[i]
var newApoinments []model.Apoinment
for _, apoinment := range *bookingItem.Apoinments {
if apoinment.StartTime.Local().After(startDate.Local()) && apoinment.EndTime.Local().Before(endDate.Local()) {
newApoinments = append(newApoinments, apoinment)
// log.Println("10 - 23", apoinment.ClientName)
}
}
*bookingItems[i].Apoinments = newApoinments
}
}
return &model.CompanyBookingItems{
Data: *existingCompany.BookingItems,
}, nil
}
but get error runtime error: invalid memory address or nil pointer dereference
How i can filter and mongodb return me only document with special ranged time apoinments of booking object?

Related

How can I convert updateMany with ArrayFilters options mongodb query into Golang?

I am facing issue to write golang code for mongodb query. I had tried to convert following mongodb query:
db.batches.updateMany(
{"batchedOrders.newOrderObject.orderDetails.trackingId" : "ORDER_JEET_2023_02_05_01"},
{ $set: { "batchedOrders.$[elem].newOrderObject.pickupDetails.note" : "Welcome" } },
{ arrayFilters: [ { "elem.newOrderObject.orderDetails.trackingId": "ORDER_JEET_2023_02_05_01" } ] }
)
Golang code:
Here b is interface{} and carrying following data:
{
"batchedOrders.$[elem].newOrderObject.dropoffDetails.recipientDetails.email": "das#rara.delivery",
"batchedOrders.$[elem].newOrderObject.orderDetails.dimensions.height": 0,
"batchedOrders.$[elem].newOrderObject.orderDetails.dimensions.length": 0,
"batchedOrders.$[elem].newOrderObject.orderDetails.dimensions.unit": "cm",
"batchedOrders.$[elem].newOrderObject.orderDetails.dimensions.width": 0,
"batchedOrders.$[elem].newOrderObject.orderDetails.orderDeliveryDetails.sla.dropoff": 1675712794,
"batchedOrders.$[elem].newOrderObject.orderDetails.parcelSize": "Medium",
"batchedOrders.$[elem].newOrderObject.orderDetails.weightDetails.billableWeight": 5,
"batchedOrders.$[elem].newOrderObject.orderDetails.weightDetails.volWeight": 5,
"batchedOrders.$[elem].newOrderObject.orderDetails.weightDetails.weight": 5,
"batchedOrders.$[elem].newOrderObject.orderDetails.weightIndex": 1,
"batchedOrders.$[elem].newOrderObject.pickupDetails.pickupIncharge.name": "Mukesh"
}
Following is the golang code:
data, _ := bson.Marshal(b)
err = bson.Unmarshal([]byte(data), &doc)
arrayFilters := options.ArrayFilters{Filters: []interface{}{bson.D{
{Key: "elem.newOrderObject.orderDetails.trackingId", Value: trackingId},
}}}
opts := options.UpdateOptions{
ArrayFilters: &arrayFilters,
}
res, err := db.Collection(BATCH_COLLECTION_NAME).UpdateMany(ctx, bson.D{{Key: "batchedOrders.newOrderObject.orderDetails.trackingId", Value: trackingId}}, bson.M{"$set": doc}, &opts)
if err != nil {
log.Println(lg.Info(err))
return false, err
}
I am getting following error:
WriteString can only write while positioned on a Element or Value but is positioned on a TopLevel
I am trying to update multiple data in mongodb database. But getting error.
In order to successfully use the UpdateMany method, you should do something similar to this:
package main
import (
"context"
"fmt"
"strings"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var (
ctx context.Context
cancel context.CancelFunc
)
type Message struct {
ID string `json:"id" bson:"id"`
Name string `json:"name" bson:"name"`
}
func main() {
ctx, cancel = context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
// set MongoDB connection
clientOptions := options.Client().ApplyURI("mongodb://root:root#localhost:27017")
mongoClient, err := mongo.Connect(ctx, clientOptions)
if err != nil {
panic(err)
}
defer mongoClient.Disconnect(ctx)
// select collection
collection := mongoClient.Database("demodb").Collection("myCollection")
defer collection.Drop(ctx)
fmt.Println("original documents")
// insert some random msg
if _, err := collection.InsertMany(ctx, []interface{}{
Message{"1", "John Doe"},
Message{"2", "Suzy Lee"},
Message{"3", "John Doe"},
}); err != nil {
panic(err)
}
// get records
var messagesTmp []bson.M
cursorTmp, err := collection.Find(ctx, bson.M{})
if err != nil {
panic(err)
}
if err := cursorTmp.All(ctx, &messagesTmp); err != nil {
panic(err)
}
for _, v := range messagesTmp {
fmt.Println(v)
}
fmt.Println(strings.Repeat("#", 100))
// update
var updateRes *mongo.UpdateResult
if updateRes, err = collection.UpdateMany(ctx,
bson.M{"name": "John Doe"},
bson.D{
bson.E{
Key: "$set",
Value: bson.D{
bson.E{
Key: "name",
Value: "John Doe - Edited",
},
},
},
},
); err != nil {
panic(err)
}
fmt.Println("num docs updated:", updateRes.ModifiedCount)
// list all
fmt.Println(strings.Repeat("#", 100))
fmt.Println("new documents")
var messages []Message
cursor, err := collection.Find(ctx, bson.M{})
if err != nil {
panic(err)
}
if err := cursor.All(ctx, &messages); err != nil {
panic(err)
}
for _, v := range messages {
fmt.Println(v)
}
}
Here, the relevant part is the // update section. First, we build the filter criteria we're going to use to fetch the documents to update. Then, we specify to $set a field name to a particular value John Doe - Edited.
The rest of the code is used to build a trivial program to demonstrate that the actual change is working. Feel free to adapt my example code to your specs and let me know if works for you too!

query with aggregate in mongodb and go (match, lookup)

I need that when passing a search parameter I can obtain the subcategories with the categories, also obtain the total data of all the subcategories. I don't know if it can be done with bson.M. I leave my code.
This function is the one I use for categories, I used it for subcategories but adding $lookup to bson.M throws an error.
func SubcategoriesGet(c *fiber.Ctx) error {
categoryCollection := config.MI.DB.Collection("subcategories")
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
var categories []models.Category
filter := bson.M{}
findOptions := options.Find()
if s := c.Query("s"); s != "" {
filter = bson.M{
"$or": []bson.M{
{
"name": bson.M{
"$regex": primitive.Regex{
Pattern: s,
Options: "i",
},
},
},
// {
// "visible": bson.M{
// "$regex": primitive.Regex{
// Pattern: s,
// Options: "i",
// },
// },
// },
},
}
}
if visible := c.Query("visible"); visible == "1" {
filter = bson.M{"visible": true}
}
if visible := c.Query("visible"); visible == "0" {
filter = bson.M{"visible": false}
}
page, _ := strconv.Atoi(c.Query("page", "1"))
limitVal, _ := strconv.Atoi(c.Query("limit", "10"))
var limit int64 = int64(limitVal)
total, _ := categoryCollection.CountDocuments(ctx, filter)
findOptions.SetSort(bson.M{"_id": -1})
findOptions.SetSkip((int64(page) - 1) * limit)
findOptions.SetLimit(limit)
// findOptions.
cursor, err := categoryCollection.Find(ctx, filter, findOptions)
defer cursor.Close(ctx)
if err != nil {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
"success": false,
"message": "Users not found",
"error": err,
})
}
for cursor.Next(ctx) {
var category models.Category
cursor.Decode(&category)
categories = append(categories, category)
}
last := math.Ceil(float64(total / limit))
if last < 1 && total > 0 {
last = 1
}
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"data": categories,
"total": total,
"page": page,
"last_page": last,
"limit": limit,
})
}
and this is the code that advances, I only need to obtain the total number of documents and be able to do a search by subcategory name.
func SubcategoriesGet(c *fiber.Ctx) error {
subcategoryCollection := config.MI.DB.Collection("subcategories")
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
var subcategory []models.Subategory
// querys
page, _ := strconv.Atoi(c.Query("page", "1")) // page
limitVal, _ := strconv.Atoi(c.Query("limit", "10")) // limit
var limit int64 = int64(limitVal)
// matchState := bson.D{}
if s := c.Query("s"); s != "" {
// bson.D{{"$regexMatch", bson.D{{"input", "$name"}, {"regex", "/g/"}}}}
// matchState = bson.M{"$match": bson.M{"wordname": bson.M{"$in": []bson.RegEx{{"^how$", "i"}}}}}
}
// pipeline
lookupState := bson.D{{"$lookup", bson.D{{"from", "categories"}, {"localField", "idcategory"}, {"foreignField", "_id"}, {"as", "category"}}}}
unwindState := bson.D{{"$unwind", bson.D{{"path", "$category"}, {"preserveNullAndEmptyArrays", false}}}}
limitState := bson.D{{"$limit", limit}}
sortState := bson.D{{"$sort", bson.D{{"_id", -1}}}}
skipState := bson.D{{"$skip", (int64(page) - 1) * limit}}
// groupState := bson.D{{"$project", bson.D{{"_id", 1}, {"name", 1}, {"category.name", 1}}}}
// orState := bson.D{{"$or", bson.D{{"name", bson.D{{"$regex", primitive.Regex{Pattern: "gec", Options: "i"}}}}}}}
// groupState := bson.D{{"$group", bson.D{{"_id", "$_id"}}}}
// countState := bson.D{{"$count", "total"}}
cursor, err := subcategoryCollection.Aggregate(ctx, mongo.Pipeline{skipState, lookupState, unwindState, limitState, sortState})
if err != nil {
panic(err)
}
// cursorTotal, err := subcategoryCollection.Aggregate(ctx, mongo.Pipeline{lookupState, unwindState, limitState, sortState})
// if err != nil {
// panic(err)
// }
// var showData []bson.M
// if err = cursor.Decode(); err != nil {
// panic(err)
// }
for cursor.Next(ctx) {
var subc models.Subategory
cursor.Decode(&subc)
subcategory = append(subcategory, subc)
}
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"data": subcategory,
// "total": ,
"page": page,
// "last_page": last,
"limit": limit,
})
}
I did tests with aggregate ($lookup, $skip, $limit, $count) etc. I still need to do a LIKE in SQL search and get the total number of documents

How do we create timeseries collections with mongodb golang driver?

I am trying to create timeseries collections => https://www.mongodb.com/developer/how-to/new-time-series-collections/#expireafterseconds with the following function
As you can see below i have tried different iterations to pass options to the CreateCollection() but nothing works. Searched for hours for an example of this and could not find any, and one would think will be easy to setup based on current documentation but hours later and here to get help
func CollectionsTimeSeries(name string) {
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
// options := {
// "TimeSeriesOptions": {
// "TimeField": "time_stamp",
// "MetaField": "stock",
// "Granularity": "minutes",
// },
// "ExpireAfterSeconds": 2592000,
// }
// options := {
// timeseries: {
// timeField: "time_stamp",
// metaField: "stock",
// granularity: "minutes",
// },
// expireAfterSeconds: 2592000
// }
options := {
"timeseries": {
"timeField": "time_stamp",
"metaField": "stock",
"granularity": "minutes",
},
"expireAfterSeconds": 2592000
}
// database.GetConnection.CreateCollection(ctx, name, {
// timeseries: {
// timeField: "time_stamp",
// metaField: "stock",
// granularity: "minutes",
// },
// expireAfterSeconds: 2592000
// })
database.GetConnection.CreateCollection(ctx, name, options)
}
Get the following errors
syntax error: unexpected {, expecting expression
syntax error: unexpected }, expecting comma or )
Use the options package to create an options instance containing time series options:
opt:=options.CreateCollection().
SetTimeseriesOptions(options.TimeSeries().
SetGranularity("...").
SetMetaField("...").
SetTimeField("..."))

Is there a better way to create a dynamic match on mongo?

I'm in the process of creating a view which shows all types of data. Currently I'm using tons of if statements to true and create a match parameter for all the different type of request. I really don't think writing out 120 possible if statements is the best way.. plus its getting hard to keep off. I'm hoping someone can point in the right direction. This is what I have so far.
func GetAllHourly(dbsession *mgo.Session, year, month, day, site, size, network, region string, code int) (items []MassAggregation, err error) {
defer dbsession.Close()
var match bson.M
if network == "openx3" {
network = "openx"
}
group := bson.M{"$group": bson.M{"_id": bson.M{"aws_region": "$aws_region", "http_request_status": "$http_request_status", "hour": "$hour", "network": "$network", "site": "$site", "size": "$size", "zone": "$zone", "extra": "$extra"}, "total": bson.M{"$sum": "$count"}}}
if site == "" && size == "" && network == "" && region == "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day}}
} else if site != "" && size == "" && network == "" && region == "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site}}
} else if site != "" && size != "" && network == "" && region == "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "size": size}}
} else if site != "" && size != "" && network != "" && region == "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "size": size, "network": &bson.RegEx{Pattern: network, Options: "i"}}}
} else if site != "" && size != "" && network != "" && region != "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "size": size, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region}}
} else if site != "" && size != "" && network != "" && region != "" && code != -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "size": size, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region, "http_request_status": code}}
} else if site == "" && size != "" && network == "" && region == "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "size": size}}
} else if site == "" && size != "" && network != "" && region == "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "size": size, "network": &bson.RegEx{Pattern: network, Options: "i"}}}
} else if site == "" && size != "" && network != "" && region != "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "size": size, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region}}
} else if site == "" && size == "" && network != "" && region == "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}}}
} else if site == "" && size == "" && network != "" && region != "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region}}
} else if site == "" && size == "" && network != "" && region != "" && code != -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region, "http_request_status": code}}
} else if site == "" && size == "" && network == "" && region != "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "aws_region": region}}
} else if site == "" && size == "" && network == "" && region != "" && code != -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "aws_region": region, "http_request_status": code}}
} else if site == "" && size == "" && network == "" && region == "" && code != -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "http_request_status": code}}
} else if site != "" && size == "" && network == "" && region == "" && code != -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "http_request_status": code}}
} else if site != "" && size == "" && network == "" && region != "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "aws_region": region}}
} else if site != "" && size == "" && network != "" && region == "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "network": &bson.RegEx{Pattern: network, Options: "i"}}}
} else if site == "" && size != "" && network == "" && region == "" && code != -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "size": size, "http_request_status": code}}
} else if site == "" && size != "" && network == "" && region != "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "size": size, "aws_region": region}}
} else if site == "" && size != "" && network != "" && region == "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "size": size, "network": &bson.RegEx{Pattern: network, Options: "i"}}}
} else if site == "" && size == "" && network != "" && region == "" && code != -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "http_request_status": code}}
} else if site == "" && size == "" && network != "" && region != "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region}}
} else if site != "" && size != "" && network != "" && region == "" && code != -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "size": size, "http_request_status": code}}
} else if site != "" && size != "" && network == "" && region == "" && code != -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "site": site, "size": size, "http_request_status": code}}
} else if site == "" && size != "" && network != "" && region == "" && code != -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "size": size, "http_request_status": code}}
} else if site != "" && size == "" && network != "" && region != "" && code == -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region, "site": site}}
} else if site != "" && size == "" && network != "" && region != "" && code != -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region, "site": site, "http_request_status": code}}
} else if site != "" && size == "" && network == "" && region != "" && code != -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "aws_region": region, "site": site, "http_request_status": code}}
} else if site == "" && size != "" && network != "" && region != "" && code != -1 {
match = bson.M{"$match": bson.M{"year": year, "month": month, "day": day, "network": &bson.RegEx{Pattern: network, Options: "i"}, "aws_region": region, "size": size, "http_request_status": code}}
}
operations := []bson.M{match, group}
err = dbsession.DB("logs").C("prod").Pipe(operations).All(&items)
return
}
As you can see it's unruly.. but i haven't found an alternative yet. I'm hoping I just haven't found the answer.
UPDATE: I've changed my approach a bit. I'm still curious if this is the best way.
func GetAllHourly(dbsession *mgo.Session, year, month, day, site, size, network, region string, code int) (items []MassAggregation, err error) {
defer dbsession.Close()
matches := []bson.M{bson.M{"$match": bson.M{"year": year, "month": month, "day": day}}}
if network == "openx3" {
network = "openx"
}
if site != "" {
matches = append(matches, bson.M{"$match": bson.M{"site": site}})
}
if size != "" {
matches = append(matches, bson.M{"$match": bson.M{"size": size}})
}
if region != "" {
matches = append(matches, bson.M{"$match": bson.M{"aws_region": region}})
}
if code != -1 {
matches = append(matches, bson.M{"$match": bson.M{"http_request_status": code}})
}
if network != "" {
matches = append(matches, bson.M{"$match": bson.M{"network": &bson.RegEx{Pattern: network, Options: "i"}}})
}
group := bson.M{"$group": bson.M{"_id": bson.M{"aws_region": "$aws_region", "http_request_status": "$http_request_status", "hour": "$hour", "network": "$network", "site": "$site", "size": "$size", "zone": "$zone", "extra": "$extra"}, "total": bson.M{"$sum": "$count"}}}
var operations []bson.M
for _, match := range matches {
operations = append(operations, match)
}
operations = append(operations, group)
err = dbsession.DB("logs").C("prod").Pipe(operations).All(&items)
return
}
bson.M{} is just named type for map[string]interface{} as you can see in docs: http://godoc.org/labix.org/v2/mgo/bson#M
So, why don't you just use it as dictionary to build custom query? You'll have much less code:
query := bson.M{}
if site != "" {
query["site"] = site
}
if size != "" {
query["size"] = size
}
}
// Then use query variable for querying mongodb

Golang find a value from a map of nested json data from MongoDB

I am trying to receive data from my MongoDB using MGO in a map of type []map[string]interface{}
My JSON looks like this -
{
"_id":"string",
"brandId":123,
"category":{
"television":[
{
"cat":"T1",
"subCategory":[
{
"subCat":"T1A TV",
"warrantyPeriod":6
}
],
"warrantyPeriod":12
},
{
"cat":"T2",
"subCategory":[
{
"subCat":"T2A",
"warrantyPeriod":18
},
{
"subCat":"T2B",
"warrantyPeriod":9
}
],
"warrantyPeriod":15
},
{
"cat":"T3",
"subCategory":[
{
"subCat":"T3A",
"warrantyPeriod":3
},
{
"subCat":"T3B",
"warrantyPeriod":5
},
{
"subCat":"T3C",
"warrantyPeriod":7
},
{
"subCat":"T3D",
"warrantyPeriod":11
}
],
"warrantyPeriod":4
}
],
"television_warrantyPeriod":24
},
"title":"BrandName"
}
I would ideally pass in the category name i.e. 'television' and cat and subCat values which could be optional.
For e.g. something like this -
{
"categorySlug": "television",
"brandId": "123",
"model": "T2"
}
In which case I would expect to find '15' which is the warrantyPeriod value for T2 if there are no T2A or T2B specified.
My query functions look like this -
var data map[string]string
err := json.NewDecoder(r.Body).Decode(&data)
log.Println(err)
var buffer bytes.Buffer
buffer.WriteString("category.")
buffer.WriteString(data["categorySlug"])
brandId, _ := strconv.Atoi(data["brandId"])
concernedbrandandcategory := database.GetMappedFields("Brands", bson.M{"brandId": brandId, buffer.String(): bson.M{"$exists": true}}, bson.M{buffer.String(): 1})
categorymap := concernedbrandandcategory[0]
log.Println(categorymap["category"]["television"], reflect.TypeOf(categorymap))
My GetMappedFields function looks like this -
func GetMappedFields(collectionName string, query interface{}, selector interface{}) (result []map[string]interface{}) {
MgoSession.DB(Dbname).C(collectionName).Find(query).Select(selector).All(&result)
return
}
I'm just not able to wrap my head around this nested structure which sometimes returns a map and sometimes an interface!
Any help would be highly appreciated!
you can do something like this
majorCat := body["categorySlug"]
category := body["category"]
subCategory := body["subCategory"]
brandId, err := strconv.Atoi(body["brandId"])
if err != nil {
log.Println(err)
}
result := database.GetMappedFields("Brands", bson.M{"brandId": brandId}, bson.M{"category": 1, "_id": 0})
internalObj := result[0]["category"].(map[string]interface{})
finalValue := internalObj["television_warrantyPeriod"]
if category != "" {
for _, v := range internalObj[majorCat].([]interface{}) {
subObj := v.(map[string]interface{})
if subObj["cat"] == category {
finalValue = subObj["warrantyPeriod"]
if subCategory != "" {
minorObj := subObj["subCategory"].([]interface{})
for _, iter := range minorObj {
kevVal := iter.(map[string]interface{})
if kevVal["subCat"] == subCategory {
finalValue = kevVal["warrantyPeriod"]
}
}
}
}
}
}
Hopefully this will do dynamically or you can create a struct so that it can directly be decoded into that cheers