How to pass variable between two queries in MongoDB? - 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().

Related

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

Multi level MongoDB object querying by key

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.

Remove records from Mongodb using shell

I have a simple collection populated with student data and I need to remove some records based on some parameters. I executed the following from mongoshell
for(i=0;i<200;i++) {
var rec = db.grades.find({student_id:i,type:'homework'}).sort({score:1}).limit(1)
db.grades.remove(rec)
}
Ideally it should remove lowest score of type homework for all student_ids. Apparently, only the last 2 records (student_id: 199) from the find parameter was purged and the rest still exists.
db.grades.find({student_id:10,type:'homework'}).sort({score:1}).limit(1)
{ "_id" : ObjectId("50906d7fa3c412bb040eb5a1"), "student_id" : 10, "type" : "homework", "score" : 6.094174990746648 }
Is it because of the aysnchoronous nature of JS / Mongo ? What are the other alternatives for solving the same?
rec is not a document, it is a database cursor. You need to actually get a document from it:
for(i=0;i<200;i++) {
var cur = db.grades.find({student_id:i,type:'homework'}).sort({score:1}).limit(1);
var actualDoc = cur.next();
db.grades.remove(actualDoc);
}
Otherwise, you're trying to remove documents based on cursor properties, which is not what you want. See also http://docs.mongodb.org/manual/core/read-operations/#cursors.
You need to query the collection and return all of the documents in the collection first before iterating through it e.g.
var collection = grades.find({'type':'homework'}).sort({'student_id',1, 'score':1})
Then iterate through the records in the variable 'collection' removing documents with the lowest score. You also have an issue assigning i as a value to student_id without assigning the documents in the collection. And according to your code you're iterating through the collection based on student id. You don't need to do this to iterate through the collection. Just query all records of type homework then remove based on parameters. If you need to assign the value of student_id to a variable (hint: as a parameter to remove records), just assign student_id to a variable like so:
var id = ['student_id']
Alternatively (and this is the way I did it), you could sort all the records first by student_id and then by score. The score should be sorted in descending order.
Then iterate through the collection using a for loop, and when the student_id changes remove the record. To recognise the change in student_id store that value in a variable outside the loop and inside the loop (as 2 separate variables) then update them as you loop through the collection. Then compare the variables and remove the record if the values of the variables are not equal.
var oldid=-1;
var cursor=db.grades.find({'type':'homework'}).sort({'student_id':1,'score':1});
while (cursor.hasNext()) {
var doc = cursor.next();
var id = doc['student_id'];
if (oldid!=id)
{
db.grades.remove(doc);
oldid=id;
}
}

Most efficient way to return document with highest DateTime value in field

I have a lucene's index with documents - all of them contain field that stores DateTime value. What would be recommended/most efficient way to extract document with highest value. How it would look like for integer values? Of course i am assuming that values are converted to string using DateTools.DateToString or similar methods.
Elaborating on Jf Beaulac answer, an example of such code may look like the one below. Please note that 'CreatedAt' field is used to store DateTime values.
//providing query that will not filter any documents
var query = new TermRangeQuery("CreatedAt", DateTools.DateToString(DateTime.MinValue, DateTools.Resolution.MINUTE), DateTools.DateToString(DateTime.MaxValue, DateTools.Resolution.MINUTE), false, false);
//providing sorting on 'CreatedAt' and returning just one result
var createdAtSerchResults = searcher.Search(query, null, 1, new Sort(new SortField("CreatedAt", SortField.LONG, true)));
//extracting CreatedAt value from returned document
var documentWithMaxCreatedAt = searcher.Doc(createdAtSerchResults.ScoreDocs.First().Doc);
var result = DateTools.StringToDate(documentWithMaxCreatedAt.Get("CreatedAt"));
Just issue a Query with a Sort descending on your field that contains the Date.
Use a Search method that takes a Sort in parameter, like this one:
IndexSearcher.Search(Query, Filter, int, Sort)

MongoDB C# offic. List<BsonObject> query issue and always olds values?

I have not clearly issue during query using two criterials like Id and Other. I use a Repository storing some data like id,iso,value. I have created an index("_id","Iso") to performs queries but queries are only returning my cursor if i use only one criterial like _id, but is returning nothing if a use two (_id, Iso) (commented code).
Are the index affecting the response or the query method are failing?
use :v1.6.5 and C# official.
Sample.
//Getting Data
public List<BsonObject> Get_object(string ID, string Iso)
{
using (var helper = BsonHelper.Create())
{
//helper.Db.Repository.EnsureIndex("_Id","Iso");
var query = Query.EQ("_Id", ID);
//if (!String.IsNullOrEmpty(Iso))
// query = Query.And(query, Query.EQ("Iso", Iso));
var cursor = helper.Db.Repository.FindAs<BsonObject>(query);
return cursor.ToList();
}
}
Data:
{
"_id": "2345019",
"Iso": "UK",
"Data": "Some data"
}
After that I have Updated my data using Update.Set() methods. I can see the changed data using MongoView. The new data are correct but the query is always returning the sames olds values. To see these values i use a page that can eventually cached, but if add a timestamp at end are not changing anything, page is always returning the same olds data. Your comments are welcome, thanks.
I do not recall offhand how the C# driver creates indexes, but the shell command for creating an index is like this:
db.things.ensureIndex({j:1});
Notice the '1' which is like saying 'true'.
In your code, you have:
helper.Db.Repository.EnsureIndex("_Id","Iso");
Perhaps it should be:
helper.Db.Repository.EnsureIndex("_Id", 1);
helper.Db.Repository.EnsureIndex("Iso", 1);
It could also be related to the fact that you are creating indexes on "_Id" and the actual id field is called "_id" ... MongoDB is case sensitive.
Have a quick look through the index documentation: http://www.mongodb.org/display/DOCS/Indexes