How to retrieve []bson.M type of map - mongodb

How to retrieve multidimensional []bson.M type of map
The data in mongo is like
"taskData" : {
"createdOn" : ISODate("2016-02-20T21:23:11.903Z"),
"Task_content" : "#bob",
"Priority" : "2",
"owner_Uname" : "alice"
}
The code through which i tried to access it
var n []bson.M
e := collection.Find(bson.M{"users."+strconv.Itoa(j)+".user_name" : r.FormValue("value[userName]")}).Select(bson.M{"taskData.owner_Uname":1,"_id":0}).All(&n)
if e != nil {
fmt.Println("Error : ",e)
}else{
fmt.Println(n[0]["taskData"])
}
getting output like this
map[owner_Uname:alice]
I need to access this resultant string with another query.
It is a interface i tried to convert it to simple map
newMap :=n[0]["taskData"].(map[string]interface{})but it gives me an runtime error interface conversion: interface {} is bson.M, not map[string]interface {}
result := rawData{}
err := collection.Find(bson.M{"user_name":n[0]["taskData"]["owner_Uname"]}).All(&result)
Now I want to use it in above query ...
Kindly help me out. Thanks in advance
Edit :-
The data in mongo is like
{
"_id" : ObjectId("56bf128f5a9a6a0ebfdd5075"),
"deadLine" : {
"Start_time" : ISODate("2016-05-24T00:00:00Z"),
"End_time" : ISODate("2016-05-29T00:00:00Z")
},
},
"taskData" : {
"createdOn" : ISODate("2016-02-20T21:23:11.903Z"),
"Task_content" : "#bob",
"Priority" : "2",
"owner_Uname" : "alice"
},
"group" : {
"1" : {
"grp_name" : "grp"
},
"2" : {
"grp_name" : "secondGrp"
}
}
That will work me too if it is done with nested struct or map in struct

I'll provide you with a general example to help you understand, since SO is not a free coding service, but a platform where peers help each other to take a grasp on the problem.
My approach is not to use bson.M at all for the returned value.
package main
import (
"fmt"
"time"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
type Baz struct {
Date time.Time
Value int
}
type Bar struct {
Name string
Baz []Baz
}
type Foo struct {
Owner string
hidden int
Bar Bar
}
const (
ds = "localhost:27017"
db = "test"
coll = "nestdemo"
)
func main() {
o := Foo{
Owner: "me",
hidden: 1,
Bar: Bar{
Name: "funky",
Baz: []Baz{
Baz{Date: time.Now(), Value: 42},
},
},
}
// CHECK ERRORS in production environments
conn, _ := mgo.Dial(ds)
defer conn.Close()
c := conn.DB(db).C(coll)
c.Insert(o)
l := &Foo{}
c.Find(bson.M{"owner": "me"}).One(l)
fmt.Printf("Loaded data: %+v\n", l)
fmt.Printf(
"You got your answer to life, the universe and all the rest at %s: %d\n",
l.Bar.Baz[0].Date.Format(time.Kitchen), l.Bar.Baz[0].Value,
)
}
You can run this program on you local machine (with the constants adjusted as needed), which should give you an output looking like this:
$ go run main.go
Loaded data: &{Owner:me hidden:0 Bar:{Name:funky Baz:[{Date:2016-02-24 09:00:06.471 +0100 CET Value:42}]}}
You got your answer to life, the universe and all the rest at 9:00AM: 42
The entry in the according collection should read something like this:
{
"_id" : ObjectId("56cd6306538ba56563bdab76"),
"owner" : "me",
"bar" : {
"name" : "funky",
"baz" : [
{
"date" : ISODate("2016-02-24T08:00:06.471Z"),
"value" : 42
}
]
}
}
A few things are to note here.
I didn't need a single character in my struct definitions to have the structs marshaled to and marshaled from BSON. It was done automagically by mgo according to the rules described in the docs. However, you can customize the behavior of the (un-)marshaling, as described there.
Unexported fields (hidden in this example) take their zero value upon unmarshalling – keep that in mind, it can bite you in the neck.
There is no need to use bson.M to handle your data, which makes life a lot easier – no manual type conversions, for example.
In summary: All you need to do is to create a struct your data can be unmarhaled into. Then you can access the various fields as usual, without string fiddling and alike. That's bit of work, but a rather trivial one, as you can see.
Note: The data model you have shown is both syntactically and conceptually incorrect. Setting aside the former for now: It is a very bad practice to have values as keys, as shown in the group subdoc. This will always force you to deal with string parsing back and forth, making your life with MongoDB as complicated as it can get as a developer.
My above suggestion assumes you will correct that into something like:
{
…
groups:[
{grp_id: 1, grp_name: "grp"},
{grp_id: 2, grp_name: "secondGrp"}
]
…
}

Related

Swift base64EncodedString produces different values from same string?

I am running this code in swift:
var testBody = [String:Any]()
testBody["f1"] = "1234"
testBody["f2"] = "4321"
var o2 = [String:Any]()
o2["ttnn"] = "wedcfqv w"
o2["ttnn1"] = "mwkcd wmd 234"
testBody["o2"] = o2
let bodyData1:Data = try JSONSerialization.data(withJSONObject:testBody,options: JSONSerialization.WritingOptions.prettyPrinted)
let bodyDataBase641 = bodyData1.base64EncodedString()
print("bodyData1: \(bodyDataBase641)")
First run bodyData1 print gives this:
bodyData1: ewogICJmMSIgOiAiMTIzNCIsCiAgImYyIiA6ICI0MzIxIiwKICAibzIiIDogewogICAgInR0bm4xIiA6ICJtd2tjZCB3bWQgMjM0IiwKICAgICJ0dG5uIiA6ICJ3ZWRjZnF2IHciCiAgfQp9
Second run bodyData1 print gives this:
bodyData1: ewogICJvMiIgOiB7CiAgICAidHRubiIgOiAid2VkY2ZxdiB3IiwKICAgICJ0dG5uMSIgOiAibXdrY2Qgd21kIDIzNCIKICB9LAogICJmMiIgOiAiNDMyMSIsCiAgImYxIiA6ICIxMjM0Igp9
My original expectation was to be able to obtain the exact same encoded base 64 string as long as I am encoding the same body data.
However, running this code twice, returns two different base 64 encoded strings as shown in the bodyData1 logs.
So, how can I ensure that as long as the body stays the same, the encoded 64 string will also always be the same?
Thats because you're storing the values in a dictionary and a dictionary is:
Every dictionary is an unordered collection of key-value pairs.
print(testBody) before encoding and you'll see that the order changes.
Check out Apple's documentation on dictionaries for more info: Docs
Decoding the strings using an online base 64 decoder shows you what's happening. The first decodes to:
{
"f1" : "1234",
"f2" : "4321",
"o2" : {
"ttnn1" : "mwkcd wmd 234",
"ttnn" : "wedcfqv w"
}
}
The second decodes to:
{
"o2" : {
"ttnn" : "wedcfqv w",
"ttnn1" : "mwkcd wmd 234"
},
"f2" : "4321",
"f1" : "1234"
}
JSON keys are by default unordered. If you want the same string, one way is to sort the keys by providing the option sortedKeys:
try JSONSerialization.data(
withJSONObject: testBody,
options: [.prettyPrinted, .sortedKeys]
)

Array typing issue in build macro

Note: My issue #4417 was closed, but I didn't want to be that guy who opens another issue for the same thing.
Based on #3132, [ { "a": 1, "b": 2 }, { "a": 2 } ] doesn't compile unless you specifically type it to Array<Dynamic> or whatever type encompasses both. That's fine I guess, but inside of the build macro below, there is nowhere for me to type the array, and I get an error.
In general, I can make map literal notation work using untyped (http://try.haxe.org/#3dBf5), but I can't do that here since my types haven't been constructed yet.
macro public static function test():Array<Field> {
var fields = Context.getBuildFields();
// parse the JSON
var o = Context.parseInlineString('{ "arr": [ { "a": 1, "b": 2 }, { "a": 2 } ] }', Context.currentPos());
// ["test" => json] map literal notation
var a = [{ expr : EBinop(OpArrow, macro $v { "test" }, o), pos : Context.currentPos() }];
// creates: "public var json:StringMap<Dynamic> = ['test' => json];"
var nf:Field = {
name : "json",
doc : "docs",
meta : [],
access : [APublic],
kind : FVar(macro : haxe.ds.StringMap<Dynamic>, { expr : EArrayDecl(a), pos : Context.currentPos() } ),
pos : Context.currentPos()
};
fields.push(nf);
return fields;
// error: Arrays of mixed types...
}
Without knowing ahead of time what the structure of the json is, is there anything I can do?
You can still use untyped, by constructing an intermediate EUntyped(o) expression (more simply macro untyped $o).
Alternatively, you can traverse the parsed object and add ECheckType to Dynamic expressions to every array, generating something like to ([...]:Array<Dynamic>).
The implementation of this would look something like calling the following checkTypeArrays function with your parsed o object, before building the map literal expression.
static function checkTypeArrays(e:Expr):Expr
{
return switch (e) {
case { expr : EArrayDecl(vs), pos : pos }:
macro ($a{vs.map(checkTypeArrays)}:Array<Dynamic>);
case _:
haxe.macro.ExprTools.map(e, checkTypeArrays);
}
}
An improvement to this would be to only wrap in (:Array<Dynamic>) the arrays that fail Context.typeof(expr).

mgo find convert a single value array to string

This is part of my collection schema in mongodb:
{ "_id" : ObjectId("55e1eef5255da6d384754642"), "name" : [ "Web, Mobile & Software Dev", "Movil y desarrollo de software" ] } { "_id" : ObjectId("55e1f2d0255da6d38475464b"), "name" : [ "IT & Networking", "TI y Redes" ] } ...
Right now i can get the info like this:
err := r.Coll.Find(bson.M{}).Select(bson.M{"name": bson.M{"$slice": []int{1, 1}}}).All(&result.Data)
but i want "name" to return a string instead of a single value array, so i dont have to index it inside my frontend if no need.
very limited comments i need 2000 poits for editing my post and add more things it seems, this is not answer but maybe, so i have to loop it?, isnt better way?
err := r.Coll.Find(bson.M{}).Select(bson.M{"name": bson.M{"$slice": []int{1, 1}}}).All(&result.Data)
if err != nil {
return result, err
}
type skillnew struct {
Id bson.ObjectId `json:"id,omitempty" bson:"_id,omitempty"`
Name string `bson:"name,omitempty" json:"name,omitempty"`
}
skillsallnew := make([]skillnew, len(result.Data))
for i := range result.Data {
skillsallnew[i] = skillnew{result.Data[i].Id, result.Data[i].Name[0]}
}

Elastic4s - finding multiple exact values for one term

I'm trying to filter a term to be matching one of the values in an array.
relaying on the ES https://www.elastic.co/guide/en/elasticsearch/guide/current/_finding_multiple_exact_values.html
GET /my_store/products/_search
{
"query" : {
"filtered" : {
"filter" : {
"terms" : {
"price" : [20, 30]
}
}
}
}
}
I tried this:
val res = ESclient.execute {
search in "index" query {
filteredQuery query {
matchall
} filter {
termsFilter("category", Array(1,2))
}
}
But got an error from ES.
How can I do that?
When calling termsFilter, the method is expecting a var args invocation of Any*, so termsFilter("category", 1, 2) would work. But termsFilter("category", Array(1,2)) is treated as a single argument, since Array is a subclass of Any of course. By adding : _ * we force scala to see it as a vars arg invocation.
So this will work:
val res = ESclient.execute {
search in "index" query {
filteredQuery query {
matchall
} filter {
termsFilter("category", Array(1,2) : _ *)
}
}
Maybe the best solution of all is to update the client to be overloaded on Iterables.

unstructred inner document with mgo

I have a document which has this following structure
{ "_id" : "736722976", "value" : { "total_visit" : 4, "FIFA World Cup 2014" : 1, "Germany" : 1, "Algeria" : 1, "Thomas Muller" : 1, "Mesut Ozil" : 1, "Monsoon" : 1, "India Meteorological Department (IMD)" : 1, "Web Exclusive" : 2, "Specials" : 1, "Tapas Pal" : 1, "Twitter Trends" : 1, "Sunanda Pushkar" : 1, "Shashi Tharoor" : 1, "AIIMS" : 1, "special" : 1 } }
THE MOST IMPORTANT thing is that the sub document structure under the key "value" is variable so I can not create a structure for that. I tried to follow the suggestion here - Unstructured MongoDB collections with mgo
And I came with this code ---
package main
import ("fmt"
"labix.org/v2/mgo" //importing mgo
"labix.org/v2/mgo/bson"
_ "reflect"
)
type AnalysisStruct struct{
Id string `bson:"_id,omitempty"`
Value bson.M `bson:",inline"`
}
func main() {
var m AnalysisStruct
//connecting to localhost mongodb
session, err := mgo.Dial("localhost")
if err != nil {
panic(err)
}
defer session.Close()
c := session.DB("my_analysis_db").C("analysis_mid_2")
iter := c.Find(nil).Iter()
for{
if iter.Next(&m){
fmt.Println(m.Value["value"]["total_visit"])
}else{
break
}
}
}
When I try to build this using go build -v -o analyzer it shows me this error---
./analyzer.go:32: invalid operation: m.Value["value"]["total_visit"] (index of type interface {})
I am terribly stuck with this. Can not get anything going. Please can somebody help?
Thanks
I cam up with this code after doing some research. Not the most optimized one for sure. But for my case it works. Took help from
http://blog.denevell.org/golang-interface-type-assertions-switch.html
https://groups.google.com/forum/#!topic/mgo-users/JYE-CP15az4
package main
import ("fmt"
"labix.org/v2/mgo" //importing mgo
"labix.org/v2/mgo/bson"
_ "reflect"
)
type AnalysisStruct struct{
Id string `bson:"_id,omitempty"`
Value bson.M `bson:",inline"`
}
func main() {
var m AnalysisStruct
//connecting to localhost mongodb
session, err := mgo.Dial("localhost")
if err != nil {
panic(err)
}
defer session.Close()
c := session.DB("consumergenepool_db").C("analysis_mid_2")
iter := c.Find(nil).Iter()
for{
if iter.Next(&m){
s := m.Value["value"].(bson.M)
data, _ := bson.Marshal(s)
var m bson.M
_ = bson.Unmarshal(data, &m)
fmt.Println(m)
for k, v := range m{
fmt.Print(k)
fmt.Print(" :: ")
fmt.Println(v)
}
}else{
break
}
}
}
Let me know your thoughts on this.
Thanks
When testing something new always use a lot of fmt.Printf's to get a feel for it, that being said.
Value bson.M `bson:",inline"`
Should be
Value bson.M `bson:"value,omitempty"`
And
fmt.Println(m.Value["value"]["total_visit"])
Should be:
fmt.Printf("%#v\n", m)
fmt.Println(m.Value["total_visit"])
Your m.Value is "value", so you can use m.Value["total_visit"] directly.
playground
//edit
You can only use inline to catch any fields that that aren't a part of the original struct, but since your struct only has 2 fields (Id and Value), you don't need it.
Now if you were to keep ,inline you would use it like this:
if v, ok := m.Value["value"].(bson.M); ok {
fmt.Println(v["total_visit"])
}
Because m.Value["value"] is an interface{}, you have to type assert it back to it's original value, bson.M before you could use it.