What You’ll Learn in This Hour:
Setting the write concern for database modify requests
Inserting new documents into a collection
Updating fields in documents that exist in a collection
Using upsert to update documents if they exist or insert them if they do not exist
Deleting documents from a collection
Checking for errors on modification requests
In the previous hours, you worked with methods to retrieve documents from a collection. This hour focuses on modifying a collection by adding, updating, and removing documents. Understanding the methods available for Collection
objects to manipulate the documents stored in the collection enables you to initially populate databases, update documents as necessary, and clean up data when it is no longer necessary.
You also learn about the write concern that MongoDB uses to ensure integrity during database write requests. The write concern specifies the level MongoDB uses to ensure that writes are completed before returning a response to the client. The higher the level of concern, the better the integrity, but there is a slight cost in response time.
Before connecting to and updating data on a MongoDB database, you need to decide what level of write concern you want to implement. Write concern describes the guarantee that the MongoDB connection provides when reporting on the success of a write operation. The strength of the write concerns determines the level of guarantee.
The basic idea is that a stronger write concern tells MongoDB to wait until the write has successfully been written to disk completely before responding. A weaker write concern might wait only until MongoDB has successfully scheduled the change to be written before responding. The downside of a stronger write concern is that MongoDB waits to respond to the client connection, so write requests are a bit slower.
The write concern can be set to one of the levels in Table 8.1. The level is set on the database connection and applies to all write operations to the database.
The getLastError
command on Database
objects enables you to configure how database connections behave with regard to write concern and timeouts. The getLastError
command is a document that describes the options used for database requests. When you make changes to documents in the MongoDB database, the options set in getLastError
define how long the connection waits to complete the operation, whether journaling should be used, and so on.
Table 8.2 lists the options you can set in the getLastError
command. Use the runCommand()
method on the Database
object to execute the getLastError
command. Consider the syntax for the getLastError
command:
myDB.runCommand( { getLastError: 1,
w: 1,
j: true,
wtimeout: 1000
} );
If a write error is detected, that error is stored and can be retrieved using the getLastError
command or getLastError()
method on the Database
object.
The getLastError()
method returns null
if the last request on the Database
object returns true
; otherwise, it returns a string containing the error message. For example, to test an add operation, you could use something similar to the following:
mongo = new Mongo('localhost');
wordsDB = mongo.getDB('words');
wordsDB.runCommand( { getLastError: 1, w: 1, j: true, wtimeout: 1000 } );
wordsColl = wordsDB.getCollection('word_stats');
wordsColl.insert({word:"the"});
lastError = wordsDB.getLastError();
if(lastError){
print("ERROR: " + lastError);
}
The getLastError
command returns an object that contains much more information about the error, including the status of the last request, the number of documents modified, and the error message. Table 8.3 lists the properties of the object the getLastError
command returned.
The following shows an example of using the getLastError
command:
mongo = new Mongo('localhost');
wordsDB = mongo.getDB('words');
wordsDB.runCommand( { getLastError: 1, w: 1, j: true, wtimeout: 1000 } );
wordsColl = wordsDB.getCollection('word_stats');
wordsColl.insert({word:"the"});
results = wordsDB.runCommand( { getLastError: 1});
if(results.err){
print("ERROR: " + results.err);
}
When performing updates on objects in MongoDB, you need to specify exactly what fields need to be changed and how they need to be changed. Unlike SQL, in which you create long query strings that define the update, MongoDB enables you to implement simple update
objects with operators that define exactly how to change the data in the documents.
You can include as many operators in the update
object as you need. The format of the update
object appears here:
{
<operator>: {<field_operation>, <field_operation>, . . .},
<operator>: {<field_operation>, <field_operation>, . . .}
. . .
}
For example consider the following object:
{
name: "myName",
countA: 0,
countB: 0,
days: ["Monday", "Wednesday"],
scores: [ {id:"test1", score:94}, {id:"test2", score:85}, {id:"test3", score:97}]
}
If you want to increment countA
field by 5
, increment countB
by 1
, set the name to "New Name"
, add Friday
to the days
array, and sort the scores
array by the score
field, you would use the following update
object:
{
$inc:{countA:5, countB:1},
$set:{name:"New Name"},
$push{days:"Friday},
$sort:{score:1}
}
Table 8.4 lists the operators that can be used in the update
object when updating documents.
Another common task when interacting with MongoDB databases is that of inserting documents into collections. To insert a document, you need to first create a JavaScript object that represents the document you want to store. Insert operations use a JavaScript object because the BSON format that MongoDB uses is based on JavaScript notation.
When you have a JavaScript version of your new document, you can store it in the MongoDB database using the insert()
method on an instance of the Collection
object that is connected to the database. The following shows the syntax for the insert()
method, where the docs
parameter can be a single document object or an array of document objects:
insert(docs)
For example, the following shows an example of inserting a simple document into a collection:
mongo = new Mongo('localhost');
myDB = mongo.getDB('myDB');
myColl = myDB.getCollection('myCollection');
myColl.insert({color:"blue", value:7, name:"Ordan"});
After objects have been inserted into a collection, you need to update them from time to time as the data changes. The update()
method on the Collection
object enables you to update documents in a collection. This method is versatile, yet fairly easy to implement. The following shows the syntax for the update()
method:
update(query, update, upsert, multi)
The query
parameter is a document that identifies which document(s) you want to change. The request matches the properties and values in the query with the fields and values of the object; only those matching the query are updated. The update
parameter is an object that specifies the changes to make to the documents that match the query. Table 8.4 lists the operators that can be used.
The upsert
parameter is a Boolean; when true
, if no objects match the query, a new document is created. The multi
parameter is also a Boolean; when true
, all documents that match the query are updated. When multi
is false
, only the first document that matches the query is updated.
For example, the following changes the category
field value to old
for items in the collection for which category
currently is new
. With upsert
set to false
, new documents are not created even if no documents have a category of new
. With multi
set to true
, all documents that match are updated:
update({category:"new"}, {$set:{categor:"old"}}, false, true);
When updating multiple documents with the update()
call, you can isolate writes to protect the documents from other writes using the $isolated:1
property in the query. This doesn’t provide an all-or-nothing atomic write; it simply inhibits other write processes from updating the same objects you are writing to. For example:
update({category:"new", $isolated:1}, {$set:{category:"old"}}, false, true);
The save()
method on Collection
objects is interesting. It can be used to insert or update a document in the database. However, it is not as directly efficient as insert()
or update()
. Still, the save()
method is easier to implement in some circumstances. For example, when you are making ad-hoc changes to objects already retrieved from MongoDB, you can use save()
without having to implement the query
and update
objects of the update()
method.
The following shows the syntax of the save()
method, where the doc
parameter is the document object to be saved to the collection:
save(doc)
Typically, when using save, the document object either is a completely new JavaScript object that you want to add to the collection or is an object you have already gotten back from the collection and made changes to, and you want to save those changes back to the database.
For example, the following code saves a change to an existing object and inserts a new one:
existingObject = myCollection.findOne({name:"existingObj"});
existingObject.name = "updatedObj";
myCollection.save(existingObj);
myCollection.save({name:"newObj"});
Another type of update that you can perform on documents is the upsert
. This involves updating the object if it exists and inserting it if it does not. Normal updates do not automatically insert objects because they incur a cost to determine whether the object exists. If you know that an object does exist, then a normal update()
is much more efficient; the same is true for an insert()
if you know that the document does not already exist.
To implement an upsert
, all you need to do is set the upsert
parameter in the update()
method to true
. This tells the request to try to update the object if it exists; otherwise, a new object with field values defined in the update
parameter of the update()
method is inserted.
For example, the following code performs an update if a document that has a color
field of azure
exists in the database; otherwise, it is created:
update({color:"azure"}, {$set:{red:0, green:127, blue:255}}, true, false);
Watch Out!
To avoid inserting the same document more than once, use upsert: true
only if the query
field is uniquely indexed.
You will need to delete documents from your MongoDB collection to keep space consumption down, improve performance, and keep things clean. The remove()
method on Collection
objects makes deleting documents from a collection simple. The syntax for the remove()
method follows:
remove([query], [justOne])
The query
parameter is a document that identifies which document(s) you want to delete. The request matches the properties and values in the query
with the fields and values of the object; only those that match the query
are updated. If no query
is provided, all the documents in the collection are deleted.
The justOne
parameter is a Boolean. When true
, only the first document that matches the query is deleted. If no query
or justOne
parameter is specified, all documents in the collection are deleted.
For example, to delete all documents in the words_stats
collection, you could use
collection = myDB.getCollection('word_stats');
collection.remove();
The following code deletes all words that start with a
from the words_stats
collection:
collection = myDB.getCollection('word_stats');
collection.remove({first:'a'}, false);
The following deletes only the first word that starts with a
from the words_stats
collection:
collection = myDB.getCollection('word_stats');
collection.remove({first:'a'}, true);
The Collection
object in the MongoDB shell provides several methods for inserting, accessing, modifying, and removing documents from collections. You can insert documents into the database using insert()
, save()
, and even update()
with upsert
. The update()
and save()
methods enable you to update existing documents. You use the remove()
method to delete one or more documents.
In this hour, you also learned about the write concern that MongoDB uses to provide different levels of integrity to database update requests. The write concern specifies the level that MongoDB uses to ensure that writes are completed before returning a response to the client. The higher the level of concern, the better the integrity, but there is a slight cost in response time. You also learned how to set the write concern and other options in the getLastError
command, as well as how to find and handle errors that result because of timeouts or write concern issues.
Q. Are writes to the MongoDB dataset atomic?
A. Sort of. Only one request can modify a collection at the same time. This ensures that writes to a single collection are atomic. However, MongoDB does not provide a direct method to ensure that writes to documents in multiple collections are atomic; you must do that programmatically in your application.
The workshop consists of a set of questions and answers designed to solidify your understanding of the material covered in this hour. Try answering the questions before looking at the answers.
1. Which write concern gives the highest level of integrity?
2. How do you limit the update
option to only a single document?
3. True or false: You can use the save()
method on Collection
objects only to save existing documents.
4. How do you insert multiple documents at the same time into a collection?
1. 1
2. Set the multi
parameter of the update()
method to false.
3. False.
4. Pass an array of JavaScript objects to the insert()
method on the Collection
object.
1. Find at least two new words that you want to add to the word_stats
collection in the example dataset. Create a shell script that uses the insert()
method to add those words.
2. Create a shell script that uses the update()
method to add a field named category
with a value of exercise
to the words you added in Exercise 1.
3. Create a shell script that retrieves words with a category of exercise
and uses remove()
to delete them.
3.14.248.69