Need help to storing an map of type interface in my mongodb database using golang - mongodb

I m in the process of creating application where my back end is in go lang and database is mongoDB. My problem is that i have a map in my struct declared like
Data struct {
data map[interface{}]interface{}
}
after adding values in to this like
var data Data
data["us"]="country"
data[2]="number"
data["mother"]="son"
I m inserting it like
c.Insert(&data)
When i insert this i m losing my key and can only see the values...
{
"_id" : Object Id("57e8d9048c1c6f751ccfaf50"),
"data" : {
"<interface {} Value>" : "country",
"<interface {} Value>" : "number",
"<interface {} Value>" : "son"
},
}
May i know any way possible to use interface and get both key and values in my mongoDB. Thanks....

You can use nothing but string as key in MongoDB documents. Even if you would define your Data structure as map[int]interface{} Mongo (don't know if mgo will convert types) wouldn't allow you to insert this object into the database. Actually, you can use nothing but string as JSON key at all as this wouldn't be JSON (try in your browser console the next code JSON.parse('{2:"number"}')).
So define your Data as bson.M (shortcut for map[string]interface{}) and use strconv package to convert your numbers into strings.
But I guess you must look at arrays/slices, as only one reason why someone may need to have numbers as keys in JSON is iterations through these fields in future. And for iterations we use arrays.
Update: just checked how mgo deals with map[int]interface{}. It inserts into DB entry like {"<int Value>" : "hello"}. Where <int Value> is not number but actually string <int Value>

Related

MongoDB: How to query over a json string?

There's a MongoDB collection that was populated with documents like this one:
{
"_id" : ObjectId("5b7f83b591fae49715443590"),
"content" : "{\n\t\"email\":\"username#domain.com\",\n\t\"country_code\": \"US\"\n}"
}
As you can see "content"has a JSON string
I was able to parse the string using JSON.parse() like:
db.getCollection('my_collection').find({}).map(function(doc){ return {'_id':doc._id, 'content': JSON.parse(doc.content)}});
Giving me an array of objects with _id and content as an object.
Is there a way to execute queries (filtering, aggregate functions) over content preferably without getting an array from map?
like you said In terms of the database content is a string. So you need to save the entire collection where content will be a object so you will be able to filtering, aggregate etc...

MongoDB check if value exists within array

I'm using MongoDB inside a twig framework. I'm trying to determine if the user has access to a certain module.
(a part of) my DB entry looks like:
_id: "579b50a4f5092761a20f4e71",
approvedModules: [
"examplemodule",
"examplemodule1",
"examplemodule2",
"examplemodule3"
],
My code looks like:
session.get('__AUTH_USER').find({ approvedModules : { '$in' : ["examplemodule"]}}, { '$exists' : true })
(the standard functions have to be in quotes).
I keeps returning false. I can only return the value if I use session.get('__AUTH_USER').approvedModules.0
I don't want to include the .0 because that might change.
What am I doing wrong?
Thanks in advance!
What am I doing wrong?
Many things. The worst one is using queries to database inside a template, but it is another problem.
You misunderstood purpose of the $in operator, which is used to match a field in the database to any element of array in the query.
To match any element of array in the collection to a single value you can do simple $eq:
session.get('__AUTH_USER').find({ approvedModules : "examplemodule"})
When you are using $in operator, you need to have 2 input arguments, the first one is the value for which you are checking the array, and the second one should be the array itself.
So, your bson element should look like this:
isModuleInArray : { '$in' : ["examplemodule","$approvedModules"] }

MongoDB: Find document given field values in an object with an unknown key

I'm making a database on theses/arguments. They are related to other arguments, which I've placed in an object with a dynamic key, which is completely random.
{
_id : "aeokejXMwGKvWzF5L",
text : "test",
relations : {
cF6iKAkDJg5eQGsgb : {
type : "interpretation",
originId : "uFEjssN2RgcrgiTjh",
ratings: [...]
}
}
}
Can I find this document if I only know what the value of type is? That is I want to do something like this:
db.theses.find({relations['anything']: { type: "interpretation"}}})
This could've been done easily with the positional operator, if relations had been an array. But then I cannot make changes to the objects in ratings, as mongo doesn't support those updates. I'm asking here to see if I can keep from having to change the database structure.
Though you seem to have approached this structure due to a problem with updates in using nested arrays, you really have only caused another problem by doing something else which is not really supported, and that is that there is no "wildcard" concept for searching unspecified keys using the standard query operators that are optimal.
The only way you can really search for such data is by using JavaScript code on the server to traverse the keys using $where. This is clearly not a really good idea as it requires brute force evaluation rather than using useful things like an index, but it can be approached as follows:
db.theses.find(function() {
var relations = this.relations;
return Object.keys(relations).some(function(rel) {
return relations[rel].type == "interpretation";
});
))
While this will return those objects from the collection that contain the required nested value, it must inspect each object in the collection in order to do the evaluation. This is why such evaluation should really only be used when paired with something that can directly use an index instead as a hard value from the object in the collection.
Still the better solution is to consider remodelling the data to take advantage of indexes in search. Where it is neccessary to update the "ratings" information, then basically "flatten" the structure to consider each "rating" element as the only array data instead:
{
"_id": "aeokejXMwGKvWzF5L",
"text": "test",
"relationsRatings": [
{
"relationId": "cF6iKAkDJg5eQGsgb",
"type": "interpretation",
"originId": "uFEjssN2RgcrgiTjh",
"ratingId": 1,
"ratingScore": 5
},
{
"relationId": "cF6iKAkDJg5eQGsgb",
"type": "interpretation",
"originId": "uFEjssN2RgcrgiTjh",
"ratingId": 2,
"ratingScore": 6
}
]
}
Now searching is of course quite simple:
db.theses.find({ "relationsRatings.type": "interpretation" })
And of course the positional $ operator can now be used with the flatter structure:
db.theses.update(
{ "relationsRatings.ratingId": 1 },
{ "$set": { "relationsRatings.$.ratingScore": 7 } }
)
Of course this means duplication of the "related" data for each "ratings" value, but this is generally the cost of being to update by matched position as this is all that is supported with a single level of array nesting only.
So you can force the logic to match with the way you have it structured, but it is not a great idea to do so and will lead to performance problems. If however your main need here is to update the "ratings" information rather than just append to the inner list, then a flatter structure will be of greater benefit and of course be a lot faster to search.

Reactive mongo fails to store BigInt

I'm using Play (2.4) with reactive mongo. I'm trying to save following document using reactive mongo:
{
"networkStart" : 42540528726795050063891204319802818560,
"networkEnd" : 42540528726795654526801011634390171648,
"lat" : 36.0833,
"lon" : 140.116
}
using following code
val record = GeoIP(... networkStart, networkEnd, lat, lng ...)
val collection: JSONCollection = reactiveMongoApi.db.collection[JSONCollection]("mycolleciton")
collection.save(Json.toJson(record)).map{ r =>
Logger.error(s"Has err: ${r.hasErrors}")
}
but nothing happens. There is no document in mongo DB and there is no error log in logs. When i try to save record with lower numbers e.g. 16777216 in place of network* attributes everything works fine.
Same for searching. When i search using query e.g. {networkStart: {$lte #someNum#}} for #someNum# equals to very big integer i get exception [NoSuchElementException: JsError.get]. When i search for lower number i get correct results.
Am i managing big numbers incorrectly? How can i store them and retrieve using reactive mongo? When i try to insert document with big number manually directly into DB it works.
Edit
I managed to get validation error by debugging. It says:
(,List(ValidationError(List(List((,List(ValidationError(List(List((,List(ValidationError(List(List((,List(ValidationError(List(List((,List(ValidationError(List(unhandled json value: 85060714218195519117058029889198843855),WrappedArray()))))),WrappedArray()))))),WrappedArray()))))),WrappedArray()))))),WrappedArray())))
where the most interesting part is: List(unhandled json value: 85060714218195519117058029889198843855). But why?

RMongo dbGetQueryForKeys(), what is the structure of "keys," and how do I sub-key them?

I am trying to query a mongo database from R using RMongo and return the values of a couple nested documents.
Looking through the documentation for RMongo, I understand the following query:
output <- dbGetQueryForKeys(mongo, 'test_data', '{"foo": "bar"}', '{"foo":1}')
Where the arguments are...
db = mongo
collection = 'test_data'
query = '{"foo": "bar"}'
keys = 'Specify a set of keys to return.'
What is the 1 in '{"foo":1}'? What is the structure of this key set? Checking against this blog post, I found a format like:
result < - dbGetQueryForKeys(mongo, "items", "{'publish_date' : { '$gte' : '2011-04-01', '$lt' : '2011-05-01'}}", "{'publish_date' : 1, 'rank' : 1}")
So, apparently, the keys need the value 1?
How would I get keys for nested documents? If I wanted something like...
output <- dbGetQueryForKeys(mongo, 'test_data', '{"foo": "bar"}', '{"foo1.foo2.foo3.foo4":1,"foo1.foo2.foo3.bar4":1}')
For nested keys, I'm currently returning something more like...
X_id
1 50fabd42a29d6013864fb9d7
foo1
1 { "foo2" : { "foo3" : { "foo4" : "090909" , "bar4" : "1"}}}
...where output[,2] is a looooong string, rather than as two separate variables for the values associated with the keys foo4 and bar4, ("090909", "1") as I would have expected.
What is the 1 in '{"foo":1}'? What is the structure of this key set?
These keys are the query projections to return for read operations in MongoDB. A value of "1" means to include a specific field and "0" excludes. The default behaviour is to include all fields in the projection.
How would I get keys for nested documents?
For nested keys, I'm currently returning something more like...
1 { "foo2" : { "foo3" : { "foo4" : "090909" , "bar4" : "1"}}}
...where output[,2] is a looooong string, rather than as two
separate variables for the values associated with the keys foo4
and bar4, ("090909", "1") as I would have expected.
The RMongo driver is returning data including the embedding hiearchy.
You can reshape & flatten the result output using the RMongo dbAggregate() command and the $project operator which is part of the Aggregation Framework in MongoDB 2.2+.
If your end goal is to extract the values from the nested object for some type of downstream processing in R this will get you there. It avoids having to build an aggregation pipeline and is a simple solution to your problem. Instead of trying to get deep into the nested structure and access bar4 directly, extract the top level of the object which will provide the long string that you've referenced.
output <- dbGetQueryForKeys(mongo, 'test_data', '{"foo": "bar"}', '{"foo1.foo2.foo3.foo4":1,"foo1":1}')
Since the output is a data.frame, you can use the 'jsonlite' library to get to your data:
library(jsonlite)
foo1 <- fromJSON(output$foo1)
bar4 <- foo1$foo2$foo3$bar4