Remove records from Mongodb using shell - mongodb

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;
}
}

Related

Need to delete mongodb collection with prefix based name

I have number of collection in my mongodb.
The collections names are like aaa_123,aaa_345,aaa_ccc,mmm,nnn and etc...
Many collections name has prefixed with aaa_ and also other collection name also present, I need to delete only the collection names prefixed with aaa_ , but in manual I deleted like db.aaa_123.drop(), its take long time to delete collection , Is there anyway to delete all collections with prefixed aaa_ in mongodb?
Anyhelp appreciated..
First Get all collection in DB to one variable then loop through that variable and check for that name in collection. If that check condition satisfies delete that collection. Check below for code sample
var collectionNames = db.getCollectionNames();
for(var i = 0, len = collectionNames.length; i < len ; i++){
var collectionName = collectionNames[i];
if(collectionName.indexOf('aaa_') == 0){
db[collectionName].drop()
}
}
Hope this helps

MongoDB: Performing actions on a field of a collection

I am very new to MongoDB (only got started out of interest last week). I am trying to figure out something and I'm not entirely sure of the terminology to go about searching for it. So I decided to make a SO question.
I created a collection called Students. Students has the fields id, name, undergrad(which is a boolean), classes(which is an array) and units(which is 3 times the number of classes the student has).
Now, I wanted to see how I could perform actions on a particular field of Students. What I did was, inserted a couple documents and purposefully did not include the units field. And I wanted to $set the units field forEach document/student that did not have the field. I did the following:
var studentDoc = db.students.find({units: {$exists:false}})
studentDoc.forEach(function(stu){
db.student.update({_id:stu._id}, {$set:{units:{$size:"$classes"}}})
}
)
Question 1: Is what I've done even remotely correct?
Question 2: When I type studentDoc after setting the var studentDoc, it doesn't print anything. But when I write
var studentDoc = db.students.find({units:{$exists:false}}).toArray()
it prints studentDoc as an array but still doesn't seem to do anything in the forEach loop.
Question 3: How do I $set the units field as 3 * (size of classes array)
I hope I have been clear in my question. I have tried searching on the MongoDB docs and google, but haven't had any luck (probably because of my lack of knowledge to search for the correct things).
Any help would be great! You can even point me in the right direction, and that'll be great!
Thank you in advance for all your help!!
I'm not sure why foreach not getting in. You can do the same with below working code.
for(i=0;i<studentDoc.length();i++){
var stud_id = studentDoc[i]._id;
var doc = db.students.findOne({"_id":stud_id})["classes"];
if(doc){
var len = doc.length;
db.students.update({"_id":stud_id},{$set:{"units":len*3}})
}
}
As far as I know, You can't use $size:"$" queries in update statement. you will get error like below:
The dollar ($) prefixed field '$size' in 'units.$size' is not valid for storage.
The return value of db.collection.find() is cursor.
In the mongo shell, if the returned cursor is not assigned to a variable using the var keyword, the cursor is automatically iterated up to 20 times to access up to the first 20 documents that match the query. To iterate manually, assign the returned cursor to a variable using the var keyword. So
var studentDoc = db.students.find({units: {$exists:false}})
You should iterator studentDoc manually.
Whereas, the cursor.toArray() returns an array that contains all the documents from a cursor. The method iterates completely the cursor, loading all the documents into RAM and exhausting the cursor. Thus
var studentDoc = db.students.find({units:{$exists:false}}).toArray()
it prints studentDoc as an array.
If you want to use forEach, here is cursor.forEach().
db.students.find({units:{$exists:false}}).forEach()
var studentDoc = db.students.find({units: {$exists:false}})
here studentDoc is a cursor, it's not printable.
you can use forEach
studentDoc.forEach(printjson);
or iterator the cursor
while (studentDoc.hasNext()) {
printjson(studentDoc.next());
}

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().

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.

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