#MongoDB - Basic Commands
##Saving Data
db //Tells you the current database
show collections //Shows the collections available in the current db
db.foo.save({_id:1, x:10}) //Save the document into the foo collection
db.bar.save({_id:1, x:10}) //Save the document into the bar collection
You can view the data using:
db.foo.find() //Normal
db.foo.find.pretty() //Formats the data to make it more viewable
db.foo.count() //Shows the number of documents in the collection
Mongo will automatically create a system.indexes
collection with an index entry for both collections for the _id field.
###_id field types The _id field can be a number of different types. For example maybe some data is better indexed as a date like log entries etc.
db.foo.save({ _id: 1 })
db.foo.save({ _id: 3.14 })
db.foo.save({ _id: "Hello" })
db.foo.save({ _id: ISODate() })
db.foo.save({ _id: { a:'X', b:2 } })
db.foo.find()
{ "_id" : 1 }
{ "_id" : 2, "value" : "replication is cool" }
{ "_id" : 3.14 }
{ "_id" : "Hello" }
{ "_id" : ISODate("2013-09-29T11:29:06.038Z") }
{ "_id" : { "a" : "X", "b" : 2 } }
The only data type which cannot be used as an _id is an array. You can of course convert the array into a byte structure and use that instead.
###Mongo ObjectId
If no _id is specified mongo will assign an ObjectId as the _id. You can see this using:
db.Users.save({name: 'John'})
db.Users.find()
{ "_id" : ObjectId("5248106f6538d4e1cf6daefd"), "name" : "John" }
The ObjectId is an amalgamation of a timestamp and an incrementing index. You can generate a new ObjectId using:
ObjectId()
ObjectId("524811b8d6f4a7be80e3b029")
ObjectId().getTimestamp()
ISODate("2013-09-29T11:41:18Z")
In the example above, we can access the timestamp using:
db.Users.findOne({name: 'John'})._id.getTimestamp()
###Optimizing Read and Writes The ObjectId has the advantage of being sequential and therefore it is faster for writing as each record is just appended on to the end of the file. However, if you need
###save v insert It is possible to save two documents with the same _id.
db.foo.save({_id:1, x:10}) db.foo.save({_id:1, name: "John"})
In this case the last entry is what is stored. So the record at _id: 1 will be pointing to {_id:1, name: "John"}. No error occurs when the second save is done.
There is another option, the update. In this case when the second entry is done it will report and error.
db.a.insert({_id:1, x:10}) db.a.insert({_id:1, name: "John"}) E11000 duplicate key error index: test.foo.$id dup key: { : 1.0 }
##Updating Data The db.update allows for a sequential update of record data.
db.foo.update(query, update, options);
The options parameter is optional. Options include update one, update many or Upsert (ie update if it exists, insert if it doesn't).
db.a.save({_id:1, x:10})
db.a.update({_id:1},{$inc:{x:1}})
db.a.find()
{ "_id" : 1, "x" : 11}
###Adding a field to a document
db.b.save({_id:1, x:10})
db.b.update({_id:1},{$set:{y:9}})
###Removing a field from a document
db.b.update({_id:1},{$unset:{y: ''}})
In this case the y value is arbitrary.
To remove the field from all fields you would use:
db.b.update({},{$unset:{y: ''}}, {multi: true})
In this case the options {multi: 1}
tells mongo to apply it to multiple documents. The selector of {}
tells it to select to all documents. You could tell it to only update certain documents based on a selection:
db.a.update({x: {$lt: 11}},{$unset:{y: ''}}, {multi: true})
This removes the field where the value of x is less than 11 for all documents that meet the criteria.
###Renaming a field in a document
db.b.save({_id:1, naem: 'John'})
db.b.find()
{ "_id" : 1, "naem" : "bob" }
db.b.update({_id:1},{$rename:{ 'naem': 'name' }})
###Adding a value to an array field
db.a.save({_id:1})
db.a.find()
{ "_id" : 1 }
db.a.update({_id:1}, {$push: {things: 'one' }})
db.a.find()
{ "_id" : 1, "things" : [ "one" ] }
db.a.update({_id:1}, {$push: {things: 'two' }})
###Add a value to a set field A set is the same as an array but it cannot contain duplicates.
db.a.update({_id:1}, {$addToSet: {things: 'two' }})
###Remove a value from an array
db.a.update({_id:1}, {$pull: {things: 'two' }})
###Remove the last item from an array
db.a.update({_id:1}, {$pop: {things: 1 }})
The 1 in this case refers to the item 1 from the end.
###Remove the first item from an array
db.a.update({_id:1}, {$pop: {things: -1 }})
The -1 in this case refers to the item 1 from the start.
###Updating Multiple Records The default when doing an update is to only update one record. Therefore if you have 4 records like this:
db.a.find()
{ "_id" : 1, "things" : [ 1, 2, 3 ]}
{ "_id" : 2, "things" : [ 2, 3 ]}
{ "_id" : 3, "things" : [ 3 ]}
{ "_id" : 4, "things" : [ 1, 3 ]}
And we do an update:
db.a.update({}, {$push: {things: 4}});
Instead of adding to all the records like you would expect it gives us:
db.a.find()
{ "_id" : 1, "things" : [ 1, 2, 3, 4 ]}
{ "_id" : 2, "things" : [ 2, 3 ]}
{ "_id" : 3, "things" : [ 3 ]}
{ "_id" : 4, "things" : [ 1, 3 ]}
So, it only add to record 1. To update multiple rows you need to set {multi:true}.
db.a.update({}, {$push: {things: 4}}, {multi:true});
db.a.find()
{ "_id" : 1, "things" : [ 1, 2, 3, 4, 4 ]}
{ "_id" : 2, "things" : [ 2, 3, 4 ]}
{ "_id" : 3, "things" : [ 3, 4 ]}
{ "_id" : 4, "things" : [ 1, 3, 4 ]}
###Updating Multiple Records based on Criteria If you want to update records which contain 2 you can do it with the following query:
db.a.update({things:2}, {$push: {things: 42}}, {multi:true});
db.a.find()
{ "_id" : 1, "things" : [ 1, 2, 3, 4, 4, 42 ]}
{ "_id" : 2, "things" : [ 2, 3, 4, 42 ]}
{ "_id" : 3, "things" : [ 3, 4 ]}
{ "_id" : 4, "things" : [ 1, 3, 4 ]}
###Find and Modify
Find and Modify will find and update one document which matches the query. Typically the query is something like {_id: 10}
.
db.foo.findAndModify({
query: <document>,
update: <document>,
upsert: <document>,
remove: <boolean>,
new: <boolean>,
sort: <document>,
fields: <document> });
By default findAndModify will return a the record before the modification unless new
is set to true. Then it will return the record after the modification. You can select the fields to return rather than the whole document. If remove is set to true then it will delete the document. upsert
will tell it to create the document if it does not already exist. remove
will delete the record. fields
tells what fields you want returned from the command in case you do not want all the fields to be returned.
db.a.findAndModify({query: {x: {$gt: 18}}, update: {$inc:{x:2}}, new: true})
This will find and update only one document.
###FindOne
findOne
returns only one document.
findOne({_id:1})
###Find
db.foo.find(query, projection)
The query
part determines the selection criteria and the projection
refers to the field that you wish to return. Please note that there is a speed cost of returning lots of unneeded fields so you should only return the smallest set of data necessary. If you do not specify a projection
then all the fields are returned. Note that unlike findOne, find returns a cursor and does not point to the data directly. You can still carry out functions on the results of the cursor like sort, skip, limit etc.
db.a.find({_id: 1})
//_id is always unique so this will return only one document
//{ "_id" : 1, "x" : 28, "y" : 2 }
db.a.find({x: 28, y: 2})
//returns all documents where x = 28 and y =2
//{ "_id" : 1, "x" : 28, "y" : 2 }
####Projections (Fields)
By default mongo return all the fields in a document. You cna specify a projection if you wish to specify which fields to return. Note: it treats both true
and 1
as true
, so a projection of db.a.find({_id: 1},{x: true, y: 1})
will return both the x and y fields as well as the _id
which is always returned. You can also tell it what fields not to return, so db.a.find({_id: 1},{_id: false})
will return all the fields except the _id
field. You can only include or exclude fields, you cannot use the projection to include and exclude fields in the same projection.
####Ranges You can also specify ranges:
db.a.find({_id: {$gt:1, $lt:4}}, {_id:1}
In this the query returns where the _id
is greater than 1 and less than 4. It also returns only the _id
field.
You can also use the $in
operator
db.a.find({_id: {$in: [1,3]}}, {_id:1})
This will return all documents where the _id
is in the set [1,3] (ie 1 or 3)
You can also find all those not in the set using:
db.a.find({_id: {$nin: [1,3]}}, {_id:1})
####Negation
You can also use negation (normally you would just use $lt
here but it is just for example):
db.a.find({_id: {$not: {$gt:3}}}, {_id:1}
####Arrays You can also find elements in an array:
db.animals.save({_id: 1, name: "cat", tags: ["cute", "land"], info: {type: 'carnivore'}})
db.animals.save({_id: 2, name: "rabbit", tags: ["cute", "land"], info: {type: 'herbivore'}})
db.animals.save({_id: 3, name: "shark", tags: ["ocean"], info: {type: 'carnivore', color: null}})
db.animals.save({_id: 4, name: "dolphin", tags: ["cute", "ocean"], info: {type: 'carnivore', color: 'grey'}})
db.animals.save({_id: 5, name: "rat", tags: ["land"], info: {type: 'omnivore'}})
To find any documents that have a tag or either 'ocean' or 'cute' use the $in
operator:
db.animals.find({tags: {$in: ['cute', 'ocean']}}, {name: 1})
{ "_id" : 1, "name" : "cat" }
{ "_id" : 2, "name" : "rabbit" }
{ "_id" : 3, "name" : "shark" }
{ "_id" : 4, "name" : "dolphin" }
To find documents that have tags of both 'cute' and 'ocean' use the $all
operator:
db.animals.find({tags: {$all: ['cute', 'ocean']}}, {name: 1})
{ "_id" : 4, "name" : "dolphin" }
To check for documents not in 'cute' or 'ocean' you can use $nin
.
db.animals.find({tags: {$nin: ['cute', 'ocean']}}, {name: 1})
{ "_id" : 5, "name" : "rat" }
####Dot Notation You can access field in a subdocument using dot notation as follows:
db.animals.find({'info.type': 'omnivore'})
//Same as db.animals.find({info: {type: 'omnivore'}})
{ "_id" : 5, "name" : "rat", "tags" : [ "land" ], "info" : { "type" : "omnivore" } }
Note that Mongo is loosely typed so there is no problem if the particular field does not exist on the document, it is just skipped if it is not there.
####Null fields A field value can be null if either it is set to the value or ```null`` or it does not exist.
db.animals.find({'info.color': 'grey'}, {name: 1, info: 1})
{ "_id" : 4, "name" : "dolphin", "info" : { "type" : "carnivore", "color" : "grey" } }
Searching for null gives us:
db.animals.find({'info.color': null}, {name: 1, info: 1})
{ "_id" : 1, "name" : "cat", "info" : { "type" : "carnivore" } }
{ "_id" : 2, "name" : "rabbit", "info" : { "type" : "herbivore" } }
{ "_id" : 3, "name" : "shark", "info" : { "type" : "carnivore", "color" : null } }
{ "_id" : 5, "name" : "rat", "info" : { "type" : "omnivore" } }
This returns where the field is null
ie for the shark and where the field does not exist at all.
####Check for field existence
To check if field exists you can use the $exists
operator.
db.animals.find({'info.color': {$exists: true}}, {name: 1, info: 1})
{ "_id" : 3, "name" : "shark", "info" : { "type" : "carnivore", "color" : null } }
{ "_id" : 4, "name" : "dolphin", "info" : { "type" : "carnivore", "color" : "grey" } }
This returns the documents which have the field, even if the value is null. the opposite of this is:
db.animals.find({'info.color': {$exists: false}}, {name: 1, info: 1})
{ "_id" : 1, "name" : "cat", "info" : { "type" : "carnivore" } }
{ "_id" : 2, "name" : "rabbit", "info" : { "type" : "herbivore" } }
{ "_id" : 5, "name" : "rat", "info" : { "type" : "omnivore" } }
Note: the existence of a field can be a useful indicator of the version of the document. So v1 of the api has one field, v2 of the api has a different field etc.
###Sorting You can sort the results (1 is ascending, -1 is descending) of a find using:
db.animals.find({}, {name: 1}).sort({name: 1})
You can also sort on multiple fields using:
db.animals.find({}, {name: 1}).sort({name: 1, 'info.type': 1})
###Limit You can limit the number of documents returned. This can be useful for paging or finding the top 10 results etc.
db.animals.find({}).limit(2)
###Skip Skip is useful for paging.
db.animals.find({}).skip(2).limit(2)