Write concern is a balance between response time(performance) and the success of a write operation(Reliability).
Write includes insert, udpate and delete.
A weak write concern: write operations return quickly, but data maybe not persist well(including replica set).
A strong write concern: clients wait after mongodb confirm the write operation suncessful.

Levels

listed from weakest to strongest

  • Unacknowledged {W:0}

    similar to errors ignored

  • Acknowledged {W:1}
    used in writing unimportant data, e.g. some operation log, user’s behavior(click, time staying in one page)

    default write concern
    the mongod confirms that it received the write operation and applied the change to the in-memory view of data
    allows clients to catch network, duplicate key, and other errors
    does not confirm that the write operation has persisted to the disk system

  • Journaled {w:1,j:true}
    used in writing key, business data, e.g. order, account

    committing the data to the journal(journaling enabled first)
    ensures that MongoDB can recover the data following a shutdown or power interruption

  • Replica Acknowledged {w:2}

    guarantee write sucessfully to one Replica Set beside the primary

Timeouts

  • set at client side
  • wtimeout: in milliseconds
  • wtimeout causes write operations to return with an error after the specified limit, even if the required write concern will eventually succeed
  • MongoDB does not “rollback” or undo modifications made before the wtimeout interval expired

getLastError()

Driver implicitly and immediately call this method after one write operation
depending on level of Write Corcern

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//after insert(), implicitly call db.getLastError(); if capturing error, assign it to err of callback function.
// when w:-1, err is always null
// when w:0, except network error, normally no other error can be captured
// when w:1, return error from mongod to err parameter
db.collection("test", {}, function(err, collection) {
collection.insert({
name: "world peace"
},
function(err, result) {
assert.equal(null, err);
console.log(result);
db.close();
})
});

Comparison Operator

Operator JavaScript Example js Example Description
$eq == {field:{$eq:value}} a == b equal to a specified value(js: === )
$gt > {field:{$gt:value}} a > b greater than
$gte >= {field:{$gte:value}} a >= b greater than or equal to
$lt < {field:{$lt:value}} a < b less than
$lte <= {field:{$lte:value}} a <= b less than or equal to
$ne != {field:{$ne:value}} a != b not equal to
$in n/a {field:{$in:[, … ]}} n/a Matches any of the values specified in an array
$nin n/a {field:{$nin:[, … ]}} n/a Matches none of the values specified in an array

Examples

1
2
3
4
5
6
//return all account documents with name "Strong"
db.account.find({name:{$eq:"Strong"}});
//ruturn all accounts whose age are less than 18
db.account.find({age:{$lte:18}});
//Return all documents in the inventory collection where the quantity does not equal 5 nor 15
db.inventory.find({quantity:{$nin:[5, 15]}});

Logical Operator

Operator JavaScript Example js Example Description
$and && {$and:[{},…{expressionN}]} x < a && x > b and, match the conditions of both clauses
$or OR {$or:[{},…{expressionN}]} x < a OR x > b or, match the conditions of either clause
$not ! {$not:[{},…{expressionN}]} !(x == y) not, do not match the query expression
$nor n/a {$nor:[{},…{expressionN}]} n/a Joins query clauses with a logical NOR returns all documents that fail to match both clauses

NOTE: OR stands for || for js opeator above.

$and example

$and performs a logical AND operation on an array of two or more expressions and selects the documents that satisfy all the expressions in the array

1
2
3
4
//AND query with multiple expressions 
db.inventory.find({$and:[{price:{$ne:1.99}},{price:{$exists:true}}]});
//implicit AND operation
db.inventory.find({price:{$ne:1.99,$exists:true}});

This query will select all documents in the inventory collection where:

  • the price field value is not equal to 1.99 and
  • the price field exists.

$nor example

1
2
//query with two expressions
db.inventory.find({$nor:[{price:19.99},{isSale:true}]});

This query will return all documents that:

  • contain the price field whose value is not equal to 19.99 and contain the isSale field whose value is not equal to true or
  • contain the price field whose value is not equal to 19.99 but do not contain the isSale field or
  • do not contain the price field but contain the isSale field whose value is not equal to true or
  • do not contain the price field and do not contain the isSale field

Field Check Operator

$exists

Matches documents that have the specified field, {field: {$exists:boolean value}} .
When boolean value is true, $exists matches the documents that contain the field, including documents where the field value is null. If boolean value is false, the query returns only the documents that do not contain the field.

1
db.inventory.find({quanity:{$exists:true, $nin : [5,15] }});

$type

$type selects the documents where the value of the field is an instance of the specified numeric BSON type.

1
db.collection.find({field:{$type:n});

NOTE:

n stands for numeric BSON type
1 for Double
2 for String
3 Object
4 Array
7 ObjectId
8 Boolean
9 Date
10 Null
11 Regular Expression
13 JavaScript
15 js with scope
16 32 bit integer
17 timestamp
18 64 bit integer
255 Min key(but query with -1)
127 Max key

Operator for Array

$all

Match arrays that contain all elements specified in the query
Like SQL’s in operator, the difference is that $all must match all values within [], but in can only match any one value within ().
{field:{$all:[value1, … valueN]}}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 
db.accounts.find({age : {$all : [16, 17]}});
// {name: 'Jobs', age: 26, age: [ 16, 18, 19 ] } : can't match
// {name: 'Bill', age: 26, age: [ 16, 17, 19 ] } : match

###elemMatch
The $elemMatch operator matches documents that contain an array field with at least one element that matches all the specified query criteria.
> Format: { <field>: { $elemMatch: { <q1>, <q2>, ... } } }
It does not need touse $elemMatch operator for single query condition

````bash
//collection scores
{ _id: 1, results: [ 82, 85, 88 ] }
{ _id: 2, results: [ 75, 88, 89 ] }
// match element
db.scores.find( { results: { $elemMatch: { $gte: 80, $lt: 85 } } } )

//collection survey
{ _id: 1, results: [ { product: "abc", score: 10 }, { product: "xyz", score: 5 } ] }
{ _id: 2, results: [ { product: "abc", score: 8 }, { product: "xyz", score: 7 } ] }
{ _id: 3, results: [ { product: "abc", score: 7 }, { product: "xyz", score: 8 } ] }
//match embeded documents
db.survey.find({results:{$elemMatch:{product:"xyz", score:{$gte:8}}}});

$size

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//return all documents in collection where **field** is an array with N elements
db.collection.find({field:{$size:2}});
```

##More on query

###Null
understand it by a sample **employee** collection
> { "_id" : 1, "name" : "Strong", "age" : null } // age is a NULL value
{ "_id" : 2, "name" : "Jacky", "age" : 33 }
{ "_id" : 3, "name" : "Garry", "addr" : 38 } // no age field

````bash
db.employee.find({age:null}); // return Garry & Strong
// only return Strong
db.employee.find({age:{$in:null,$exists:true}});

$where

$where provides flexibility
use the $where operator to pass either a string containing a JavaScript expression or a full JavaScript function to the query system
cannot take advantage of indexes

different expression, same result

1
2
3
4
5
6
7
db.employee.find({age:{$gt:35}});
//Reference the document in the JavaScript expression or function using either **this** or **obj**
db.employee.find({$where:"this.age > 35"});
db.employee.find("this.age>35");

fn = function() {return this.age > 35};
db.employee.find(fn);

sort

1
2
db.employee.find().sort({age:1});  //ascending sequence by age,  yourger first
db.employee.find().sor({age:-1}); //descending order by age, older first

skip & limit

1
db.employee.find().skip(10).limit(20); // return 20 records from the tenth record

$mod

Format: { field: { $mod: [ divisor, remainder ] } }

$regex

regular expression

Syntax:
{ : { $regex: /pattern/, $options: ‘‘ } }
{ : { $regex: ‘pattern’, $options: ‘‘ } }
{ : { $regex: /pattern/ } }

need more steps

$text

$text performs a text search on the content of the fields indexed with a text index.

Syntax: { $text: { $search: , $language: } }

need more steps

Thought: use “user story” with acceptance criteria is a best practice in scrum process, no one use “use case”.

User story

lightweight

a short description of something that can be written on a card,
focused on the value or result they get from doing this thing
Format: As an [actor] I want [action] so that [achievement]
A User Story doesn’t capture all the details, it’s an informal support for the discussion.

Acceptance criteria

Writing the acceptance criteria is the first step of fleshing out the details of your user story.

define the boundaries of a user story, and are used to confirm when a story is completed and working as intended

example

As a conference attendee, I want to be able to register online, so I can register quickly and cut down on paperwork, the acceptance criteria could include:

  1. A user cannot submit a form without completing all the mandatory fields
  2. Information from the form is stored in the registrations database
  3. Protection against spam is working
  4. Payment can be made via credit card
  5. An acknowledgment email is sent to the user after submitting the form.

Use case

heavyweight
use case describes a “Normal Flow” of steps and/or actions and “Alternative Flows” which are detailed.

formal specification, usually created as a formal document, detail description of a set of interactions between a system and and one or more roles, roles can be people or systems, including something as below,

  • Use case title
  • Rationale/description/goal
  • Actor/user
  • Preconditions (the things that must have already happened in the system)
  • Standard path or Main success scenario (what will usually happen, described as a series of steps)
  • Alternate paths or Extensions(variations on the above/edge cases)
  • Post conditions (what the system will have done by the end of the steps).

resource

Team work is a must practice to achieve a big software developing goal today, there are many people involved in same project, a bunch of tools make good cooperation, better communication,

  • Infrastructure support: ESB, MQ, …
  • projecct management, scheoudule, execution
  • engineering process tool
  • requirement specification: trace change
  • design document
  • IDE: VS Studio, sublime, webstorm, text editor,
  • testing case
  • software quality tools
  • maintenanec - refactor, re-engineering
  • Configurationn and deployment tools
  • modern communication tool: email, live meeting, screen share,..
  • prototying method
  • agile/ scrum

Tips: retrieve previous commands issued in shell with up or down arrow key (Windows something like, C:\Users\myaccount.dbshell)

Start Shell

1
2
3
4
5
6
7
//start shell without connection to a database
mongo --nodb

//execute js file
mongo localhost:27017/testDB file.js
//alternative use load function n the shell
load("file.js") // execute js, file.js located on "data" directory

Basic commands

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
use <db_name>				// switch current db to db_name
show dbs / databases // list all databases on server
show collections / tables // list all tables on current db
db or db.getName) // show current db in shell
//
show roles // list all roles of current db
show users // list all users of current db
show profile
//how to get command reference in the shell
help or db.help() or db.collection.help()

//database can created automatically when saving data to MongoDB in shell
//Delete a database
db.dropDatabase() //drop current dtabase, delete all associated files
//Delete a collection
db.collection.drop() //remove table and index
//running in secure mode
db.auth() //authenticate user
// refer to another database using same connection
db.getSiblingDB(); //without explicitly switch the current database

CRUD at mongo shell

Overview

1
2
3
4
5
6
7
8
9
10
table = db.myCollection;	//table refer a specific collection
table.find(); //return a cursor
table.findOne(); //return a single document or null
table.count(); //count of documents
table.save(); //insert new or update existing document
table.insert(); //insert new document
table.update(); //update existing document
table.remove(); //delete existing document
//build index
table.createIndex();

Create&Update

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Loop samples in shell
use my //switch current db to my
for( var i=1;i<=200;i++) db.my.save({tag:"number",val:i});
for( var i=201;i<=250;i++) db.my.save({tag:i});
//it command
it //iterate cursor
//Loop to return all
var cursor = db.my.find();
//method I
while( cursor.hasNext()) {
printjson(cursor.next());
}
//method II
cursor.forEach(printjson);
//method III
var myArray = db.my.find().toArray();
printjson(myArray[2]);
//update
db.my.update({val:6},{$set:{tag:"NUMBER"}});
// to very update
db.my.find().limit(20);

Query

1
2
3
4
5
6
7
//SQL: select tag, val from my where tag = "number"
db.my.find({tag:"number"}).count();
db.my.find({tag:"number"},{val:true,tag:true}).limit(16);
db.my.findOne({tag:"number"},{val:true});
db.my.find({tag:"number"},{val:true,tag:true}).forEach(printjson);
//SQL: select * from my where tag > 200
db.my.find({tag:{$gt:200}}).forEach(printjson);

Delete

1
2
3
4
//remove() function
db.my.remove({tag:"NUMBER"});
// to verify
db.my.find().limit(20);