How to do multi-level pull of array element in mgo? - go

I want to do a multi-level array element delete. My Structs are as follows:-
type Company struct {
Id bson.ObjectId `bson:"_id,omitempty"`
CompanyName string
Process []ProcessItem
}
type ProcessItem struct{
SortOrder int
Documents []DocumentTemplate
}
type DocumentTemplate struct {
Id bson.ObjectId `bson:"_id,omitempty"`
TemplateName string
}
I want to delete an object of type DocumentTemplate. The DocumentTemplate is a struct array in ProcessItem which is a struct array in Company struct. I have Company Id(field of struct Company) and TemplateName(field of struct DocumentTemplate).
I tried the below mgo pull query but it is not working.
c := db.C("company")
pullQuery := bson.M{"process": bson.M{"documents.templatename": "xyz"}}
err := c.Update(bson.M{"_id": "123"}, bson.M{"$pull": pullQuery})
Please point out the mistakes I made here. Thanks.
Edit:
Adding one example document for the clarity of the question
{
"_id" : ObjectId("573da7dddd73171e42a84045"),
"companyname" : "AAA",
"process" : [
{
"processname" : "Enquiry",
"sortorder" : 0,
"documents" : [
{
"templatename" : "xyz",
"processname" : "Enquiry"
},
{
"templatename" : "ss",
"processname" : "Enquiry"
}
]
},
{
"processname" : "Converted",
"processtype" : 1,
"sortorder" : 2,
"documents" : [
{
"templatename" : "dd",
"processname" : "Converted"
},
{
"templatename" : "fg",
"processname" : "Converted"
}
]
}
]
}
I need to pull out just one DocumentTemplete record, like the one below:
{
"templatename" : "xyz",
"processname" : "Enquiry"
}
N.B: TemplateName will be unique inside a Company.

You'll need to use the $ positional operator (https://docs.mongodb.com/manual/reference/operator/projection/positional/). In order to be able to use that you'll also have to add to your query the following:
"process.documents.templatename": "xyz"
Your Update statement should look like this:
c := db.C("company")
pullQuery := bson.M{"process.$.documents": bson.M{"templatename": "xyz"}}
err := c.Update(bson.M{"_id": "123", "process.documents.templatename": "xyz"}, bson.M{"$pull": pullQuery})

You can pull values in array from the array in mongo record
change2 := bson.M{
"$pull": bson.M{"sapinfo.systemstatus": bson.M{"$in": tags}},
}

Related

Go Template - remove specific field

I am having following data format:
{"time":"2022-08-24T06:00:00Z","duration":0,"level":"OK","data":{"series":[{"name":"gnb_kpi","tags":{"ID":"1017","_field":"Success_rate%","cluster_id":"ec17-1017","swversion":"6.0"},"columns":["time","_value"],"values":[["2022-08-24T06:00:00Z","100"]]}]},"previousLevel":"CRITICAL","recoverable":true}
I want to remove the _time field from the columns array and similarily the timestamp from values array. The output I want is like this:
{"time":"2022-08-24T06:00:00Z","duration":0,"level":"OK","data":{"series":[{"name":"gnb_kpi","tags":{"ID":"1017","_field":"Success_rate%","cluster_id":"ec17-1017","swVersion":"6.0"},"columns":["_value"],"values":[["100"]]}]},"previousLevel":"CRITICAL","recoverable":true}
I used the online service JSON-to-Go to generate a data structure that corresponds to your input. It produced
type AutoGenerated struct {
Time time.Time `json:"time"`
Duration int `json:"duration"`
Level string `json:"level"`
Data struct {
Series []struct {
Name string `json:"name"`
Tags struct {
ID string `json:"ID"`
Field string `json:"_field"`
ClusterID string `json:"cluster_id"`
Swversion string `json:"swversion"`
} `json:"tags"`
Columns []string `json:"columns"`
Values [][]interface{} `json:"values"`
} `json:"series"`
} `json:"data"`
PreviousLevel string `json:"previousLevel"`
Recoverable bool `json:"recoverable"`
}
The algorithm is simple:
parse JSON into the generated structure
iterate over series
find the position of time field in columns
remove the corresponding data elements from values
https://go.dev/play/p/rjnvmdBXCE4
Output is (beautified)
{
"time": "2022-08-24T06:00:00Z",
"duration": 0,
"level": "OK",
"data": {
"series": [
{
"name": "gnb_kpi",
"tags": {
"ID": "1017",
"_field": "Success_rate%",
"cluster_id": "ec17-1017",
"swversion": "6.0"
},
"columns": [
"_value"
],
"values": [
[
"100"
]
]
}
]
},
"previousLevel": "CRITICAL",
"recoverable": true
}
As you see, no time

Concatenate declared variable with random string

It is possible, using Terratest, to declare a tfvars file with the following variable:
bar = {
name = "test"
domain = "test.com"
regions = [
{ location = "France Central", alias = "france" }
]
}
But include a random prefix to the bar.domain string inside the go code?
I'm using terraformOptions as follows:
terraformOptions := &terraform.Options{
TerraformDir: sourcePath,
VarFiles: []string{variablesPath + "/integration.tfvars"},
}
It is not ideal for one to make use of the tfvars file directly to take the input in case of tests. More on this here
To answer your question :
You can use something similar to this :
options := terraform.Options{
TerraformDir: "sourcePath",
Vars: map[string]interface{}{
"name": "test",
"domain": addRandomprefix()+"test.com",
"region ": map[string]interface{}{
"location" : "France Central",
"alias" : "france",
},
},
}
Just create your own custom addRandomprefix() method. I hope this helps :)

Keeping multiple types ( nesting types / embedding types ) in a single collection:

I want to keep all of the types in a single collection named “BenchmarkDatasets”. Do I need to declare the subtypes(LatData, AggregateData, MetaData) differently or do I just need to accept that I’ll have a collection for every type?
Any help is greatly appreciated.
Here's the Schema I generated:
type LatData {
LatResults: [[Int ]]
LatResultSize: [Int ]
}
type AggregateData {
EVRCounter: Int
EVRLatencyTotal: Int
EVRLatencyAverage: Float
LatTestCount: Int
LatencyTotal: Int
LatencyAverage: Float
}
type MetaData {
StartTimeUTC: String
EndTimeUTC: String
StartTimeLocal: String
EndTimeLocal: String
}
type BenchmarkDataset {
LatData: LatData
AggregateData: AggregateData
MetaData: MetaData
}
type Query {
allBenchmarkDatasets: [BenchmarkDataset!]
}
And here's the data I want to shove into "BenchmarkDatasets":
{
"MetaData" :
{
"StartTimeUTC" : "Sun Oct 18 21:41:38 2020\n",
"EndTimeUTC" : "Sun Oct 18 21:45:38 2020\n",
"StartTimeLocal" : "Sun Oct 18 16:41:38 2020\n",
"EndTimeLocal" : "Sun Oct 18 16:45:38 2020\n"
},
"AggregateData" :
{
"EVRCounter" : 3,
"EVRLatencyTotal" : 70,
"EVRLatencyAverage" : 23.333333333333332,
"LatTestCount" : 159,
"LatencyTotal" : 11871,
"LatencyAverage" : 74.660377358490564
},
"LatData" :
{
"LatResultSize" :
[
4,
4,
4
],
"LatResults" :
[
[
0,
2,
"zoom",
"latencymonitor"
],
[
1,
1,
"zoom",
"latencymonitor"
],
[
2,
1,
"zoom",
"latencymonitor"
],
[
3,
1,
"dota2",
"dota2"
]
]
}
}
Also, I know that my data is not well formatted(specifically the 2d "LatData" array that contains 2 ints and 2 strings), and any data format tips are also appreciated.
Figured out the issue! I specifically needed to use the "#embedded" directive to make my schema look something like this:
type LatData #embedded {
LatResults: [[Int ]]
LatResultSize: [Int ]
}
type AggregateData #embedded {
EVRCounter: Int
EVRLatencyTotal: Int
EVRLatencyAverage: Float
LatTestCount: Int
LatencyTotal: Int
LatencyAverage: Float
}
type MetaData #embedded {
StartTimeUTC: String
EndTimeUTC: String
StartTimeLocal: String
EndTimeLocal: String
}
type BenchmarkDataset {
LatData: LatData
AggregateData: AggregateData
MetaData: MetaData
}
type Query {
allBenchmarkDatasets: [BenchmarkDataset!]
}

Find all elements sorted by best matches

I have some entities in my database called "events". Each of these events contain an array of string, called "tags".
I want to make a query to get all the events matching an array of tags that I will give in parameter.
BUT, I want these events to be sorted like:
The first one is the one containing most of the tags I give in parameter.
The second one is the second one containing most of the tags I give in parameter.
And so on.
If there are more than one event containing the same amount of tags I want them to be sorted by their "name" property in alphabetical order.
Example:
"name" = "event1", "tags" = ["food", "music", "gaming", "sport"]
"name" = "event2", "tags" = ["gaming"]
"name" = "event3", "tags" = ["music", "sport"]
"name" = "event4", "tags" = ["food", "music", "gaming", "sport"]
"name" = "event5", "tags" = ["music", "sport", "coding"]
"name" = "event6", "tags" = ["coding"]
"name" = "event7", "tags" = ["food", "gaming", "sport"]
The array of tags that I give in parameter for this example is: ["food", "music", "gaming", "sport"]
The result for this example will be an array of events, containing in that order:
event1, event4, event7, event3, event5, event2
To get all the events containing the tags I simply make a query with the "$or" operators. This allowed me to get all the events if they contained at least one of the tag given in parameter.
Code:
var events []model.Event
var MyQuery []map[string]interface{}
for i := 0; i < len(tags); i++ {
currentCondition := bson.M{"tags": tags[i]}
MyQuery = append(MyQuery, currentCondition)
}
err := dbEvents.C(collectionEvents).Find(bson.M{"$or": OrQuery}).All(&events)
But i really don't know how to sort them like I showed you.
package main
import (
"fmt"
"github.com/ahmetb/go-linq"
)
type T struct {
Name string
Tags []string
}
func main() {
params := []string{"food", "music", "gaming", "sport"}
t := []T{
T{Name: "event1", Tags: []string{"food", "music", "gaming", "sport"}},
T{Name: "event2", Tags: []string{"gaming"}},
T{Name: "event3", Tags: []string{"music", "sport"}},
T{Name: "event4", Tags: []string{"food", "music", "gaming", "sport"}},
T{Name: "event5", Tags: []string{"music", "coding", "sport"}},
T{Name: "event6", Tags: []string{"coding"}},
T{Name: "event7", Tags: []string{"food", "gaming", "sport"}},
}
var result []T
linq.From(t).SortT(func(t1 T, t2 T) bool {
var rs1 []string
linq.From(t1.Tags).IntersectByT(linq.From(params), func(str string) string {
return str
}).ToSlice(&rs1)
var rs2 []string
linq.From(t2.Tags).IntersectByT(linq.From(params), func(str string) string {
return str
}).ToSlice(&rs2)
return len(rs1) > len(rs2)
}).ToSlice(&result)
fmt.Printf("%+v", result)
}
[{Name:event1 Tags:[food music gaming sport]} {Name:event4 Tags:[food music gaming sport]} {Name:event7 Tags:[food gaming sport]} {Name:event3 Tags:[music sport]} {Name:event5 Tags:[music coding sport]} {Name:event2 Tags:[gaming]} {Name:event6 Tags:[coding]}]
Above program sorts the array as per your requirements, Hope this will help you.

Nested struct conversion from mgo (mongodb library) to golang struct?

I have a struct like this:
type ArticleDocument struct {
ArticleID string `json:"article_id" bson:"article_id"`
ArticleTitle string `json:"article_title" bson:"article_title"`
Author string `json:"author" bson:"author"`
Board string `json:"board" bson:"board"`
Content string `json:"content" bson:"content"`
Date string `json:"date" bson:"date"`
IP string `json:"ip" bson:"ip"`
MessageConut struct {
All int `json:"all" bson:"all"`
Boo int `json:"boo" bson:"boo"`
Count int `json:"count" bson:"count"`
Neutral int `json:"neutral" bson:"neutral"`
Push int `json:"push" bson:"push"`
} `json:"message_count,inline" bson:"message_count,inline"`
Messages []interface{} `json:"messages" bson:"messages"`
URL string `json:"url" bson:"url"`
}
In MongoDB, my document looks like:
{
"_id" : ObjectId("5ab1da8133691b034b2be31d"),
"article_id" : "M.1521548086.A.DCA",
"article_title" : "some title",
"author" : "somebody",
"board" : "some board",
"content" : "some content",
"date" : "Tue Mar 20 20:14:42 2018",
"ip" : "1.1.1.1",
"message_conut" : {
"all" : 15,
"boo" : 0,
"count" : 14,
"neutral" : 1,
"push" : 14
},
"messages" : [],
"url" : "https://xxx.xxx.xxx"
}
In my Golang code, i am trying to use mgo to query this document and print it out, however, all document fields are converted to golang struct correctly except the nested document "MessageConut", all the values in "All", "Boo", "Count", ...etc are zero:
message_count":{"all":0,"boo":0,"count":0,"neutral":0,"push":0}"
Could you please guide how do I solve this issue?

Resources