Multi level MongoDB object querying by key - mongodb

If you only know the key name (say "nickname"), but not the exact path to that key in the object.
e.g. nickname may be at the first level like:
{"nickname":"Howie"}
or at the second level:
{"user":{"nickname":"Howie"}}
Is it possible to query for nickname equal "Howie" that would return both documents?

Unfortunately there is no wild card that allows you to search for a field at any level in the db. If the position is not relevant and you can modify the document structure you have 2 choices here. You can store your document as
{ fieldname:"nickname", value : "Howie" }
{ fieldname:"user/nickname", value: "Howie" }
You can then query using
db.so.find({fieldname:/nickname/, value:"Howie"})
Alternatively you can store as
db.so.insert({value:"Howie", fieldpath:["nickname"]})
db.so.insert({value:"Howie", fieldpath:["user", "nickname"]})
The advantage with the second approach is that you can now index {fieldpath:1, value:1} and a query on it such as
db.so.find({fieldpath:"nickname", value:"Howie"})
will be an indexed query.

Related

MongoDB Complex Query with Java

We have following structure in MongoDB documents.
{
"id":"1111",
"keys":[
{
"name":"Country",
"value":"USA"
},
{
"name":"City",
"value":"LongIsland"
},
{
"name":"State",
"value":"NewYork"
}
]
}
Now using Springframework Query object, I figured out a way to pull the details using below syntax
query.addCriteria(
Criteria.where("keys.value").is(countryparam).
andOperator(
Criteria.where("keys.value").is(stateparam)
)
);
Two issue with this query model.
First issue is it is irrelevant if countryparam and stateparam are actually meant to match Country key name and State key name respectively. If just the values matches, the query returns the document. Means, if I have Country and City params, this just works if user passes Country and City values, even if they are swapped. So how can I exactly compare City to cityparam and State to Stateparam?
More complexity is if I have to extract the document basing on multiple key value pairs, I should be correspondingly able to match key name with respective value and query the document. How can I do this?
Thanks in advance!

Add a record to an Algolia Index only if it does not exists

I was wondering how can i POST in a single request (without fetching results for the given attribute) a pretty simple record to an Algolia Index without creating repeated instances.
e.g:
category: {
name: String // This should be unique
}
There isn't such "addObject if not exists" feature based on the record content but if you use the category name as the objectID of your record; the second time you'll add the object, it will just replace the previous instance.
{
objectID: "mycategoryname",
moreattributes: "if needed",
[...]
}
Would that work?

How to pass variable between two queries in MongoDB?

I want to put the query result from one collection in a variable and use it as input for query in another collection. The queries look like this as follows:
Query 1:
var ID=db.User.findOne({Name:"Ivan"}, {ID: 1});
db.Artists.find({"Listeners.ID":ID});
Query 2:
var Friends=db.Users.find({Friends:x});
//Users.Friends is an array of interger identifier for User
db. Artists.find({"Listeners.ID":{$in:Friends}});
But they all don't work. How to write the right one?
The query db.User.findOne({Name:"Ivan"}, {ID: 1}); does not return a single value, it returns the document, reduced to the field you requested. What you get is an object, with two fields: _id (because you didn't explicitly exclude it) and ID (when it exists in the document). Your var ID looks like this:
{
_id:ObjectId(<long hex string>),
ID:<value>
}
So when you want to query by the ID value, you need to specify it:
db.Artists.find({"Listeners.ID":ID.ID});
Regarding your second query: when you use find instead of findOne you get a cursor object which can then be used to retrieve the individual documents using cursor.next() or cursor.toArray().

Search for ObjectId of a document: pymongo

I want to access a document in collection by 'name' attribute for getting its ObjectId so that i can insert that unique objectid to other document for reference.
cursorObject = db.collectionIngredient.find({'name': 'sugar'})
I want _id field of cursorObject.
cursorObject.'_id' or cursorObject._id not working.
I have tried __getitem__, __getattribute__ and so much internet surfing but couldn't able to find a way.
Please help
First, as #jjmartinez pointed out, find returns a cursor, which you need to iterate over, in order to get hold of the documents returned by your query. The _id field belongs to the documents, not the cursor.
I'm guessing that in your case the name is unique, so you can avoid cursor/iterating if you use find_one instead of find. Then you get the document directly.
Then, to access the _id, you just need a standard dict-item access:
id = doc['_id']
So we get:
ingredient = db.collectionIngredient.find_one({'name': 'sugar'})
if ingredient is not None:
id = ingredient['_id']
else:
id = None
When you do cursorObject = db.collectionIngredient.find({'name': 'sugar'}) you have a collection of documents, not a single element. So you need to explore all the collection. You need to iterate inside the cursor:
try:
cursorObject = db.collectionIngredient.find({'name': 'sugar'})
except:
print "Unexpected error:", sys.exc_info()[0]
for doc in cursorObject:
print doc
Here you have the Pymongo Tutorial

Composite views in couchbase

I'm new to Couchbase and am struggling to get a composite index to do what I want it to. The use-case is this:
I have a set of "Enumerations" being stored as documents
Each has a "last_updated" field which -- as you may have guessed -- stores the last time that the field was updated
I want to be able to show only those enumerations which have been updated since some given date but still sort the list by the name of the enumeration
I've created a Couchbase View like this:
function (doc, meta) {
var time_array;
if (doc.doc_type === "enum") {
if (doc.last_updated) {
time_array = doc.last_updated.split(/[- :]/);
} else {
time_array = [0,0,0,0,0,0];
}
for(var i=0; i<time_array.length; i++) { time_array[i] = parseInt(time_array[i], 10); }
time_array.unshift(meta.id);
emit(time_array, null);
}
}
I have one record that doesn't have the last_updated field set and therefore has it's time fields are all set to zero. I thought as a first test I could filter out that result and I put in the following:
startkey = ["a",2012,0,0,0,0,0]
endkey = ["Z",2014,0,0,0,0,0]
While the list is sorted by the 'id' it isn't filtering anything! Can anyone tell me what I'm doing wrong? Is there a better composite view to achieve these results?
In couchbase when you query view by startkey - endkey you're unable to filter results by 2 or more properties. Couchbase has only one index, so it will filter your results only by first param. So your query will be identical to query with:
startkey = ["a"]
endkey = ["Z"]
Here is a link to complete answer by Filipe Manana why it can't be filtered by those dates.
Here is a quote from it:
For composite keys (arrays), elements are compared from left to right and comparison finishes as soon as a element is different from the corresponding element in the other key (same as what happens when comparing strings à la memcmp() or strcmp()).
So if you want to have a view that filters by date, date array should go first in composite key.