10gen Mongo For Developers Week 2 Notes

The mongo shell has a javascript interpreter.

A primary key is immutable: it cannot be changed.

The findOne() method on a collection pulls a random document.

findOne( { whereKey : value } ) method is used like a where clause in SQL, pulling all documents from a collection with key = value. Using two key value pairs, such as {whereKey1 : value1, whereKey2 : value2} in the first argument of the findOne() method is like using the AND condition in a SQL where clause.

The findOne( { whereKey : value } , {selectKey , booleanValue } ) method is used like a where clause and a select list in SQL, pulling all documents from a collection with wherekey = value and displaying those keys with selectKey = true. If "_id" is not set to false, the object id will always be shown. Omitting the second argument in the findOne() parameter is like using a SELECT * in SQL.

These arguments also work with the find() parameter.

Calling find() alone one a collection will display all documents within a collection. By default, only 20 documents are returned in a batch, but by typing "it", the next batch can be seen. A cursor holds this information which is cleared in 10 minutes by default.

The $gt, $gte, $lt, $lte operators are used in queries to search for inequalities on numbers for greater than, greater than or equal to, less than, and less than or equal to, respectively. For example, to find all people in a collection with an age greater than 50, use the following:

db.people.find( { age : { $gt : 50 } } ) ;

To find people over 50 and less than or equal to 55, use the following:

db.people.find( { age : { $gt : 50 , $lte : 55 } } ) ;

Mongo is a schemaless database: documents within collections may have different fields, and those fields with the same name may even store different datatypes. To find all documents that utilize a particular field, use the $exists operator:

db.people.find( { "name" : { $exists : true} } ;

To find all documents that utilze a paricular field which has a particular data type, use the $type operator:

db.people.find( { "name" : { type : 2 } } ) ;

The $type is specified by numbers which are the corresponding type values from the BSON specification. The $type for string is 2.

$regex allows you to use regular expression matching for string datatypes.

The $or operator, unlike the other query operators listed so far, is a "prefix operator", it comes before the subqueries it connects together. It takes an array of a set of documents which hold queries which you could give separately. For example:

db.people.find( { $or : [ {name : { $regex : "e$" } }, { age : { $exists : true } } ] } );

You can explicitly call a logical and with the $and operator.

The following query does not perform a BETWEEN but only retrieves results less than 60:

db.scores.find( { score : { $gt : 50 }, score : { $lt : 60 } } );

This is because the last one wins if the syntax is entered as such. This would be a good time to use the $and operator.

Matching is polymorphic in mongo. The following will return all documents that have a field with the value of "pretzel" and all fields that have a value of an array that contains value:

db.accounts.find( { favorites : "pretzel" } ) ;

There is no recursing through searches: searches only hit the top level elements of the field you specify.

The $in and $all operators work like the $and and $or operators in that they take an operand; however, the $in and $all operators take as an operand an array and do what you would expect from them.

db.accounts.find( { favorites : { $all : [ "pretzels", "beer" ] } } ) ;  
db.accounts.find( { name : { $in : [ "Howard" , "John" ] } } ) ;

Querying nested documents using the dot notation.

The following will not retrieve the inserted document:

db.users.insert ( { name : "richard" , email : { work : "richard@10gen.com" , personal : "kreuter@example.com" } } ) ;  
db.users.find ( { email : { personal : "kreuter@example.com", work : "richard@10gen.com" } );  
db.users.find( { email : { work : "richard@10gen.com" } } ) ;

The first find won't work because BSON stores the documents in binary, the order of which a document was stored affects. The second won't work because the dot operator is needed unless the entire subdocument was queried by example and in the correct order.

The find() method actually returns a cursor that could be returned to a variable. A variable used in this manner has a variety of methods that can be called on it. hasNext() returns a boolean value signifying whether or not there is more data in the cursor. next() returns the next document. When the find() method is used without storing the results in a variable, the mongo console is configured to display the results of the cursor.

To return the results of a query in reverse lexicographical order, or descending order for numbers, use the sort() method on a cursor with an argument of a field as the key and -1 as the value:

cur = db.people.find(); null;  
cur.sort( { name : -1 } ) ; null;  
cur = db.scores.find( { type : "exam" } ).sort( { score : -1 } ) ; null;

null; must be tacked onto the end of the cursor to prevent the mongo console from displaying it and going through a cursor. The following returns false:

cur = db.people.find() ;  
cur.hasNext() ;

The sort(), limit(), and skip() method return a cursor, so either of these is fine:

cur = db.people.find(); null ;  
cur.limit(2).sort( { name : -1 } ) ; null;  
cur.sort( { name : -1 } ).limit(2); null;

"It is important to realize that the sort and limit method modify the information that is transmitted over to the database. These methods cannot be applied to a cursor after having begun retrieving documents from a database, or even checking whether the cursor hasNext(). This is because the sort() or the limit() needs to be processed in the server, not the client." For example, the following fails with a "JavaScript execution failed: query already executed at ..."

cur = db.people.find(); null;  
cur.hasNext();  
cur.limit(5);

The skip() method on a cursor returns

The sort(), skip(), and limit() methods are applied to a cursor in the server in this order, regardless of the order they were applied to the cursor object before it was sent to the server. So the following still applied the three methods in the order ot sort(), skip(), and then limit():

cur = db.people.find().limit(5).skip(2).sort( { names : -1 } ) ; null;  
cur;

The count() method retrieves a number of the number of results that would have been found by querying by an example. The following would return a count of all scores of type essay with a score greater than 90:

db.scores.count( { type : "essay" , score : { $gt : 90 } } ) ;

Updating

The update() method takes at least two arguments. The first argument is a query, similar to a WHERE clause in SQL. The second argument is a document that you want to replace it with. It is important to realize that a single element in a document cannot be changed by this method: the update() method is a "wholesale replacement", thus the following will show no results:

db.people.insert( { name: "matthew" , age : 22 , profession : "IT Engineer" } ) ;  
db.people.update( { name: "matthew" } , { age : 23 } ) ;  
db.people.find( {name: "matthew" } ) ;

To update specific fields in a document, use the $set operator which takes an operand of a document containing the field you wish to change and the value you wish to change it to. If the field does not exist in the document, it will be created:

> db.people.insert ( { name : "matthew" } ) ;  
> db.people.update ( { name : "matthew" } , { $set : { age : 22 } } ) ;  
> db.people.find( { name : "matthew" } ) ;  
{ "_id" : ObjectId("51665ed2d603819069760504"), "age" : 22, "name" : "matthew" }

To increment a numeric field in a document, simply use the $inc operator, which takes an operand of the field to increment with the value to increment by, in the update() method:

> db.people.update ( { name : "matthew" } , { $inc : { age : 1 } } ) ;  
> db.people.find ( { name : "matthew" } ) ;  
{ "_id" : ObjectId("51665ed2d603819069760504"), "age" : 23, "name" : "matthew" }

If the field doesn't exist, the field will be created with the value of the increment step.

db.people.insert ( { name : "bob" } ) ;  
db.people.update ( { name : "bob" } , {$inc : { age : 1 } } ) ;  
db.people.find( { name : "bob" } ) ;  
"_id" : ObjectId("51665fcdd603819069760505"), "age" : 1, "name" : "bob" }

To remove a field from a record, use the $unset operator with an operand in the update() method:

db.people.update ( { name : "Jones" } , { $unset : { age : 1 } } ) ;

****Dot notation, $push, $pop, $pull, $pushAll, $pullAll, and $addToSet all manipulate arrays within documents.

To $set a single element in an array within a document, use the dot notation:

db.arrays.insert( { _id : 0, a : [1,2,3,4] } ) ;  
db.arrays.update( { _id : 0 } , { $set : { "a.2" : 5 } } ) ;

$push adds an element to the right side of an array:

db.arrays.update( { _id : 0 } , { $push : { a : 1 } } );

$pop removes an element from the right side of an array with a positive argument:

db.arrays.update( { _id : 0 } , { $pop : { a : 1 } } );

$pop removes an element from the left side of an array with a negative argument:

db.arrays.update( { _id : 0 } . { $pop : {a : -1} } ) ;

$pushAll adds multiple elements to an array:

db.arrays.update ( { _id : 0 } , { $pushAll : { a : [ 7,8,9] } } ) ;

$pull removes an element from the array regardless of its position:

db.arrays.update ( { _id : 0 } , { $pull : { a : 7 } } ) ;

$pullAll removes a set of elements from the array regardless of their position:

db.arrays.update( { _id : 0 } , { $pullAll : { a : [1,3,6] } } ) ;

$addToSet will only add an element to an array if it doesn't previously exist in an array:

db.arrays.update( { _id : 0 } , { $addToSet : { a : 1 } } ) ;

Passing an array to an $addToSet will result in that array being inserted as an element within the array; it will not add each item in the array to the main array.

To perform an upsert on a collection, pass a third argument to the update() method containing the document { upsert : true } which will perform an upsert if the document specified in the first argument cannot be found. For example, the first box will show nothing if Charlie isn't already in the people collection, while the second box will show Charlie:

db.people.update( { name : "Charlie" }, { $set : { age : 40 } } ) ;  
db.people.find( { name : "Charlie" } );





> db.people.update( { name : "Charlie" }, { $set : { age : 40 } }, { upsert : true} ) ;  
> db.people.find( { name: "Charlie" } );  
{ "_id" : ObjectId("51679751b7ed9e9a6c1d42dd"), "age" : 40, "name" : "Charlie" }

To perform a multi-update on a collection, pass a third argument to the update() method containing the document { multi : true } which will update multiple documents that match the query in the first argument. If you fail to pass this third argument, even if multiple documents match the query in the first argument, mongo will only update whichever document happens to be first retrieved by the query.This is totally contrary to a RDBMS. You can pass an empty document {} to the first argument in order to perform a select on the whole collection (this is also true for .find() ). For example, to add a new field to every document in the collection:

db.people.update( {}, { $set : { title : "Dr" } }, { multi : true } ) ;

The remove() method takes a first argument with the same semantics as that of find(). Unlike the update() method, the remove() method does not need a { multi : true } argument. There are two ways to remove all documents in a collection, by using the remove() method with no argument passed, or the drop() method. drop() is more efficient, as the remove() method will have to pass through each document in the collection, whereas a drop() method will simply drop them all. This is similar to a TRUNCATE in SQL, except that a TRUNCATE does not kill all the associated indexes, whereas a drop() does.

update() and remove() are not atomic with respect to multiple readers and writers, only to a single reader or writer. In other words, a single client will always have a read consistent view on the data he has changed, but multiple clients are not guarenteed this read consistency without additional modification. This is a bummer to learn and will be important to remember.

The getLastError command tells whether or not the last write operation succeded can be executed by the following:

db.runCommand( { getLastError : 1 } ) ;

The drivers for the various languages connecting to Mongo are written with the language in mind. For example, pymongo, which is the python driver to Mongo, uses underscores between words instead of camelCase. So the findOne() method in the mongo shell is actually find_one() in pymongo. For another example, if the key in mongo is a string, the key need not be placed in quotes, but in python, the keys must be placed in quotes or it will search for a variable. The same goes for the $ operators, like '$gt' and '$lt'. Another example: a selector in the mongo shell uses true or false, whereas in python uses 1 or 0 to display or not, respectively. Another example: the sort() method takes a constant, pymongo.DESCENDING as opposed to a negative number. Another example: the sort() method in pymongo isn't passed a JSON document like cur.sort( { student_id, 1} ) as it is in the mongo shell, , but rather: cur.sort('student_id', pymongo.ASCENDING); Python's dictionaries do not retain order, while mongo does.

mongoshell: cur = grades.find( { type

As mentioned previously, the following order is always applied regardless of how it is entered: sort, skip, limit.

Updating data in pymongo. The save() command is a convenience method which combines inserting and updating: if an _id is set it assumes there is an update, if there is no _id set when calling save it assumes it is an insert. The two types of updates are wholesale updates and selective updates.

The find_and_modify() function in pymongo can be used to produce a sequence number. It takes three named parameters: query, update, upsert, and new. Passing a document like {'$inc':{'value':1}} to the update parameter initiates the increment. Passing true to the new parameter will return the newest value that was updated instead of the older value.

I will update more as I continue.


Comments

Add Comment

Name

Email

Comment

Are you human? * three = 3