How to query complex structures in MongoDB? - mongodb

I persist my Python classes to JSON and write them to MongoDB. I'm using a JSON Encoder which has been presented here. This results in a slight complex JSON structure which does not follow the simple "string" key/values in all the MongoDB tutorials. Here is an excerpt of a class written to JSON:
{
"_id" : ObjectId("51f2397c86a49a5e6dec4633"),
"__module__" : "experiment.experimentmanager",
"experiments" : {
"FOO" : [
{
"__module__" : "experiment.experiment",
"enable_routing_table_trace" : false,
"__class__" : "Experiment",
"scenario_name" : "foobar",
"enable_network_visualize" : false
},
}
I'm wondering how I could check for example if there is a key "FOO" in experiments using MongoDBs find? Thanks in advance!

To check if field exists use$exists operator.
To access complex structures use dot notation. For example:
db.inventory.find( { "experiments.FOO": { $exists: true} } )

This query should work:
db.collection.find({
"experiments.FOO": {
$exists:true
}
});

Related

Can elastic search provide nested json results?

I know that elastic search provides good support for nested json. It has very good support for nested objects with advance indexing.
So, when I make a nested query in elastic search, can the query result be obtained in original nested form ? Or is the query result in flattened form like that in lucene or solr ?
Note: I have used apache solr and lucene before. And, I am evaluating other different search platforms for better support for nested json objects.
I'm giving you a simple example of results maintaining the depth.
PUT people { "mappings": {
"list": {
"properties": {
"name": {
"type": "nested"
}
}
} } }
PUT people/list/1 { "age" : "19", "name" : [
{
"first" : "John",
"last" : "Smith"
} ] }
PUT people/list/2 { "age" : "23", "name" : [
{
"first" : "Wilber",
"last" : "Smith"
} ] }
GET people/list/_search { "query": {
"match_all": {} } }
As far as I understand, you'll prefer nested mapping to object mapping. Because object would flatten results. See this for reference:
https://www.elastic.co/guide/en/elasticsearch/reference/2.4/nested.html

How to re-map the fields of a mongodb collection?

Picture it -- I have a collection, and it has a particular mapping.
Pretend:
{
"field": "lala",
"subdoc": {
"otherfield": "la",
"etcfield": "la"
}
}
And I need to convert that to a different data structure:
{
"field-gets-renamed": "lala",
"subdoc-has-different-stuff-in-it": {
"something": "la",
"something-else": "la"
}
}
What is the typical way of doing that? (Is there one?)
Do I read collection1 doc by doc and write it to a different collection?
Or is there a way to just remap the fields in collection1?
I would greatly appreciate some example, as I am a novice to mongodb.
You should make use of the $rename operator
In your case it would be:
db.collectionName.update({}, { $rename : { 'field' : 'field123', 'subdoc' : 'subdoc123', 'subdoc.otherfield' : 'subdoc.otherfield123', 'subdoc.etcfield' : 'subdoc.etcfield123'} }, false, true);
P.S: I havent tested the above command.

Aggregating filter for Key

If I have a document as follows:
{
"_id" : ObjectId("54986d5531a011bb5fb8e0ee"),
"owner" : "54948a5d85f7a9527a002917",
"type" : "group",
"deleted" : false,
"participants" : {
"54948a5d85f7a9527a002917" : {
"last_message_id" : null
},
"5491234568f7a9527a002917" : {
"last_message_id" : null
}
"1234567aaaa7a9527a002917" : {
"last_message_id" : null
}
},
}
How do I do a simple filter for all documents this have participant "54948a5d85f7a9527a002917"?
Thanks
Trying to query structures like this does not work well. There are a whole whole host of problems with modelling like this, but the most clear problem is using "data" as the names for "keys".
Try to think a little RDBMS like, at least in the concepts of the limitations to what a database cannot or should not do. You wouldn't design a "table" in a schema that had something like "54948a5d85f7a9527a002917" as the "column" name now would you? But this is essentially what you are doing here.
MongoDB can query this, but not in an efficient way:
db.collection.find({
"participants.54948a5d85f7a9527a002917": { "$exists": true }
})
Naturally this looks for the "presence" of a key in the data. While the query form is available, it does not make efficient use of such things as indexes where available as indexes apply to "data" and not the "key" names.
A better structure and approach is this:
{
"_id" : ObjectId("54986d5531a011bb5fb8e0ee"),
"owner" : "54948a5d85f7a9527a002917",
"type" : "group",
"deleted" : false,
"participants" : [
{ "_id": "54948a5d85f7a9527a002917" },
{ "_id": "5491234568f7a9527a002918" },
{ "_id": "1234567aaaa7a9527a002917" }
]
}
Now the "data" you are looking for is actual "data" associated with a "key" ( possibly ) and inside an array for binding to the parent object. This is much more efficient to query:
db.collection.find({
"participants._id": "54948a5d85f7a9527a002917"
})
It's much better to model that way than what you are presently doing and it makes sense to the consumption of objects.
BTW. It's probably just cut and paste in your question but you cannot possibly duplicate keys such as "54948a5d85f7a9527a002917" as you have. That is a basic hash rule that is being broken there.

MongoDB query with multiple search terms(regexes) in c# with 10gens driver?

If we have
Blog{
Name 'Blog1'
Tags ['testing','visual-studio','2010','c#']
}
Blog{
Name 'Blog2'
Tags ['parallel','microsoft','c#']
}
Via the console we can execute and find all blog posts that contains some of the provided tags:
db.BlogPost.find({ 'Tags' : { '$regex' : ['/^Test/', '/^microsoft/', '/^visual/', '/^studio/', '/^c#/'] } });
How can we write the same query in c# 10gens driver ?
Is there any alternative if it can not be written via the 10gens c# driver ?
Query.Match only support one regex. Can we provide him multiple regexes, or we should combine
Query.Or(Query.Match("Test"), Query.Match("Micro"), Query.Match("Visual"))
I've managed to solve it with
I've managed to do it with
{ "$or" : [{ "Tags" : /^programm/i }, { "Tags" : /^microsoft/i }, { "Tags" : /^visual/i }, { "Tags" : /^studio/i }, { "Tags" : /^assert/i }, { "Tags" : /^2010/i }, { "Tags" : /^c#/i }] }
But something tells me that this is an ugly hack that may result in performance issues. What do you think guys ?
The final answer to the problem can be found on:
Official mongodb forum
Yes, the MongoDB c# driver should automatically do the right thing with instances of System.Text.RegularExpressions.Regex.
So you should be able to build the exact same query, except that you would use instances of Regex for ^Test, ^microsoft, ^visual, etc instead of strings.

How do I perform this query in both Mongo console and Mongoid?

I'm trying to learn how to query Mongo in more advanced ways. Let's say my data structure is this:
{ "_id" : "-bcktick-ajman-ae-292932", "asciiname" : "`Ajman",
"alternatenames" : [
{
"isolanguage" : "no",
"alternateNameId" : 2698358,
"alternateName" : "Ajman"
},
{
"isolanguage" : "en",
"alternateNameId" : 2698357,
"alternateName" : "Ajman"
}
]
}
So to find Ajman is easy:
db.cities.find({ "asciiname":"`Ajman" })
However, I want to find cities that only have an isolanguage of en. You'll notice the isolanguage is in the alternatenames array.
But I can't seem to find the correct syntax in either the client or mongoid
Either one (or both) would be greatly appreciated.
Thanks
I think you are looking for the $elemMatch keyword:
db.cities.find(
{ 'alternatenames' : {
$elemMatch: { isolanguage: 'en'}
}
})
Currently, Mongoid does not have a helper for $elemMatch so you have to pass in the raw query:
City.where({ :alternatenames => { '$elemMatch' => { :isolanguage => 'en' } } })
More info here on $elemMatch here:
http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24elemMatch
http://www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29
More info on Mongoid support for $elemMatch here:
http://groups.google.com/group/mongoid/browse_thread/thread/8648b451e3957e12
https://github.com/mongoid/mongoid/issues/750