when you can have circular links of hte same type (users apear everywhere) its more a graph database than document. http://www.sarahmei.com/blog/2013/11/11/why-you-should-never-use-mongodb/
$ ./mongo > use mongo-db > show collections > db.meetups.insert({name:"MEAN SF Developers"}) > show collections > db.meetups.find() > db.meetups.insert({name:"MEAN SF Developers", speaker: "Mike Moser") > db.meetups.find()
Create db.scores.save({a: 99}); //This says, "save the document '{a: 99}' to the 'scores' collection." db.scores.find(); for(i=0; i<10; i++) { db.scores.save({a: i, exam: 5}) }; // Since the shell only displays 10 results at time, you'll need to enter the 'it' command to iterate over the rest.finding all documents where a == 2: Query (Read) db.scores.find({a: 2}); documents where a > 15? db.scores.find({a: {'$gt': 15}}); Operators $lt - '<', $lte - '<=', $gte - '>=', $ne - '!=', $in - 'is in array', $nin - '! in array' db.scores.find({a: {'$in': [2, 3, 4]}}); db.scores.find({a: {'$gte': 2, '$lte': 4}}); Updates Now create a couple documents like these for updating, and Make sure they were saved by called db.users.find(): db.users.save({name: 'Johnny', languages: ['ruby', 'c']}); db.users.save({name: 'Sue', languages: ['scala', 'lisp']}); Update the first document like so: db.users.update({name: 'Johnny'}, {name: 'Cash', languages: ['english']}); Update Operators The previous update replaced the entire document, but MongoDB also supports partial updates to documents. For example, you can set a value: db.users.update({name: 'Cash'}, {'$set': {'age': 50} }); You can also push and pull items from arrays: db.users.update({name: 'Sue'}, {'$pull': {'languages': 'scala'} }); db.users.update({name: 'Sue'}, {'$push': {'languages': 'ruby'} }); Delete db.users.remove({name: 'Sue'}); //delete matching documents only db.scores.remove(); //To delete everything from a collection: CRUDMongoDB documents are BSON documents. BSON is a binary representation of JSON with additional type information. In the documents, the value of a field can be any of the BSON data types, including other documents, arrays, and arrays of documents. A collection is a group of related documents that have a set of shared common indexes. Collections are analogous to a table in relational databases. find db.users.find({age:{'gt' : 18}}).sort({age:1}) // Specify in the sort parameter the field or fields to sort by and a value of 1 or -1 to specify an ascending or descending sort respectively. db.users.find( { age: { $gt: 18 } }, { name: 1, address: 1 } ).limit(5) // age is the query criteria, name and address are projection, you can include or exclude a field (via 0 or 1) Except for excluding the _id field in inclusive projections, you cannot mix exclusive and inclusive projections. To suppress the _id field from the result set, specify _id: 0 in the projection document. db.students.find() .skip(pageNumber > 0 ? ((pageNumber-1)*nPerPage) : 0) // skip(n): skips the first n records. e.g. for paged result .limit(nPerPage) .forEach( function(student) { print(student.name + "<p>"); } ); Consider
using range-based pagination for these kinds of tasks. That is, query
for a range of objects, using logic within the application to determine
the pagination rather than the database itself. This approach features
better index utilization, if you do not need to easily jump to a
specific page. AND / OR db.inventory.find( { type: 'food', price: { $lt: 9.95 } } )
db.inventory.find( { $or: [ { qty: { $gt: 100 } }, { price: { $lt: 9.95 } } ] } ) For fields that contain arrays, MongoDB provides the following projection operators: $elemMatch,$slice, and $. For related projection functionality in the aggregation framework pipeline, use the $projectpipeline stage. Cursor By default, the server will automatically close the cursor after 10 minutes of inactivity or if client has exhausted the cursor. To override this behavior, you can specify the noTimeout wire protocol flag in your query; however, you should either close the cursor manually or exhaust the cursor. In the mongo shell, you can set the noTimeout flag: var myCursor = db.inventory.find().addOption(DBQuery.Option.noTimeout); Cursor Isolation Because the cursor is not isolated during its lifetime, intervening write operations on a document may result in a cursor that returns a document more than once if that document has changed. To handle this situation, see the information on snapshot mode. Index var typeValue = <someUserInput>;
db.inventory.find( { type: typeValue } ); To improve the performance of this query, add an ascending, or a descending, index to theinventory collection on the type field. [1] In the mongo shell, you can create indexes using the db.collection.ensureIndex() method: db.inventory.ensureIndex( { type: 1 } )
Write In MongoDB, write operations target a single collection. All write operations in MongoDB are atomic on the level of a single document. No insert, update, or remove can affect more than one document atomically. db.users.update( { age: { $gt: 18 } }, { $set: { status: "A" } }, { multi: true } ) This update operation on the users collection sets the status field to A for the documents that match the criteria of age greater than 18. with upsert flag if can not find the document will create one. The db.collection.save() method can either update an existing document or insert a document if the document cannot be found by the _id field. Write Concern Write concern describes the guarantee that MongoDB provides when reporting on the success of a write operation. a weak write concern, write operations return quickly. Read Isolation MongoDB allows clients to read documents inserted or modified before it commits these modifications to disk, regardless of write concern level or journaling configuration. As a result, applications may observe two classes of behaviors: For systems with multiple concurrent readers and writers, MongoDB will allow clients to read the results of a write operation before the write operation returns. If the mongod terminates before the journal commits, even if a write returns successfully, queries may have read data that will not exist after the mongod restarts. Atomicity / Transaction The modification of a single document is always atomic, even if the write operation modifies multiple embedded documents within that document. No other operations are atomic. If a write operation modifies multiple documents, the operation as a whole is not atomic, and other operations may interleave. You can, however, attempt to isolate a write operation that affects multiple documents using the isolation operator. db.users.insert({name:"john", age:26, groups:["news", "sport"]}) queries select documents from a single collection. To manually compare the performance of a query using more than one index, you can use the hint()method in conjunction with the explain() method. The key decision in designing data models for MongoDB applications revolves around the structure of documents and how the application represents relationships between data. There are two tools that allow applications to represent these relationships: references and embedded documents. references normalized. Applications can resolve these references to access the related data In general, use normalized data models: when embedding would result in duplication of data but would not provide sufficient read performance advantages to outweigh the implications of the duplication. to represent more complex many-to-many relationships. to model large hierarchical data sets. References provides more flexibility than embedding. However, client-side applications must issue follow-up queries to resolve the references. In other words, normalized data models can require more round trips to the server. See Model One-to-Many Relationships with Document References for an example of referencing. For examples of various tree models using references, see Model Tree Structures. embedded denormalized, Embedded documents capture relationships between data by storing related data in a single document structure. MongoDB documents make it possible to embed document structures as sub-documents in a field or array within a document. These denormalized data models allow applications to retrieve and manipulate related data in a single database operation. In general, embedding provides better performance for read operations, as well as the ability to request and retrieve related data in a single database operation. Embedded data models make it possible to update related data in a single atomic write operation. However, embedding related data in documents may lead to situations where documents grow after creation. Document growth can impact write performance and lead to data fragmentation. Furthermore, documents in MongoDB must be smaller than the maximum BSONdocument size. To interact with embedded documents, use dot notation to “reach into” embedded documents. See query for data in arrays and query data in sub-documents for more examples on accessing data in arrays and embedded documents. Operational Factors and Data Models Document Growth Atomicity Sharding Indexes Split large Number of Collections e.g. to seperate log types for efficient batch processing Time to live (TTL) GridFS GridFS is a specification for storing and retrieving files that exceed the BSON-document size limit of 16MB. Model One-to-One Relationships with Embedded Documents {
_id: "joe",
name: "Joe Bookreader"
}
---> {
patron_id: "joe",
street: "123 Fake Street",
city: "Faketon",
state: "MA",
zip: "12345"
} Model One-to-Many Relationships with Embedded Documents one-to-many relationship between patron and address data, the patron has multiple address entities. { _id: "joe", name: "Joe Bookreader" } { patron_id: "joe", street: "123 Fake Street", city: "Faketon", state: "MA", zip: "12345" } { patron_id: "joe", street: "1 Some Other Street", city: "Boston", state: "MA", zip: "12345" } TO: { _id: "joe", name: "Joe Bookreader", addresses: [ { street: "123 Fake Street", city: "Faketon", state: "MA", zip: "12345" }, { street: "1 Some Other Street", city: "Boston", state: "MA", zip: "12345" } ] } Model One-to-Many Relationships with Document References publisher and book relationships, advantage of referencing over embedding to avoid repetition of the publisher information { title: "MongoDB: The Definitive Guide", author: [ "Kristina Chodorow", "Mike Dirolf" ], published_date: ISODate("2010-09-24"), pages: 216, language: "English", publisher: { name: "O'Reilly Media", founded: 1980, location: "CA" } } { title: "50 Tips and Tricks for MongoDB Developer", author: "Kristina Chodorow", published_date: ISODate("2011-05-06"), pages: 68, language: "English", publisher: { name: "O'Reilly Media", founded: 1980, location: "CA" } } keep the publisher information in a separate collection from the book collection and store books as its arrays. if the number of books per publisher is unbounded, this data model would lead to mutable, growing arrays { name: "O'Reilly Media", founded: 1980, location: "CA", books: [12346789, 234567890, ............................................] } { _id: 123456789, title: "MongoDB: The Definitive Guide", author: [ "Kristina Chodorow", "Mike Dirolf" ], published_date: ISODate("2010-09-24"), pages: 216, language: "English" } { _id: 234567890, title: "50 Tips and Tricks for MongoDB Developer", author: "Kristina Chodorow", published_date: ISODate("2011-05-06"), pages: 68, language: "English" } To avoid mutable, growing arrays, store the publisher reference inside the book document: {
_id: "oreilly",
name: "O'Reilly Media",
founded: 1980,
location: "CA"
}
{ _id: 123456789, title: "MongoDB: The Definitive Guide", author: [ "Kristina Chodorow", "Mike Dirolf" ], published_date: ISODate("2010-09-24"), pages: 216, language: "English", publisher_id: "oreilly" } { _id: 234567890, title: "50 Tips and Tricks for MongoDB Developer", author: "Kristina Chodorow", published_date: ISODate("2011-05-06"), pages: 68, language: "English", publisher_id: "oreilly" } Modeling Trees Model Tree Structures with Parent References db.categories.insert( { _id: "MongoDB", parent: "Databases" } )
db.categories.insert( { _id: "dbm", parent: "Databases" } ) db.categories.insert( { _id: "Databases", parent: "Programming" } ) db.categories.insert( { _id: "Languages", parent: "Programming" } ) db.categories.insert( { _id: "Programming", parent: "Books" } ) db.categories.insert( { _id: "Books", parent: null } ) The query to retrieve the parent of a node is fast and straightforward: db.categories.findOne( { _id: "MongoDB" } ).parent
You can create an index on the field parent to enable fast search by the parent node: db.categories.ensureIndex( { parent: 1 } )
You can query by the parent field to find its immediate children nodes: db.categories.find( { parent: "Databases" } )
The Parent Links pattern provides a simple solution to tree storage but requires multiple queries to retrieve subtrees. Model Tree Structures with Child References in addition to the tree node, document stores in an array the id(s) of the node’s children. db.categories.insert( { _id: "MongoDB", children: [] } )
db.categories.insert( { _id: "dbm", children: [] } ) db.categories.insert( { _id: "Databases", children: [ "MongoDB", "dbm" ] } ) db.categories.insert( { _id: "Languages", children: [] } ) db.categories.insert( { _id: "Programming", children: [ "Databases", "Languages" ] } ) db.categories.insert( { _id: "Books", children: [ "Programming" ] } ) The query to retrieve the immediate children of a node is fast and straightforward: db.categories.findOne( { _id: "Databases" } ).children
You can create an index on the field children to enable fast search by the child nodes: db.categories.ensureIndex( { children: 1 } )
You can query for a node in the children field to find its parent node as well as its siblings: db.categories.find( { children: "MongoDB" } )
The Child References pattern provides a suitable solution to tree storage as long as no operations on subtrees are necessary. This pattern may also provide a suitable solution for storing graphs where a node may have multiple parents. Model Tree Structures with an Array of Ancestors in addition to the tree node, document stores in an array the id(s) of the node’s ancestors or path. db.categories.insert( { _id: "MongoDB", ancestors: [ "Books", "Programming", "Databases" ], parent: "Databases" } )
db.categories.insert( { _id: "dbm", ancestors: [ "Books", "Programming", "Databases" ], parent: "Databases" } ) db.categories.insert( { _id: "Databases", ancestors: [ "Books", "Programming" ], parent: "Programming" } ) db.categories.insert( { _id: "Languages", ancestors: [ "Books", "Programming" ], parent: "Programming" } ) db.categories.insert( { _id: "Programming", ancestors: [ "Books" ], parent: "Books" } ) db.categories.insert( { _id: "Books", ancestors: [ ], parent: null } ) The query to retrieve the ancestors or path of a node is fast and straightforward: db.categories.findOne( { _id: "MongoDB" } ).ancestors You can create an index on the field ancestors to enable fast search by the ancestors nodes: db.categories.ensureIndex( { ancestors: 1 } )
You can query by the field ancestors to find all its descendants: db.categories.find( { ancestors: "Programming" } )
The Array of Ancestors pattern provides a fast and efficient solution to find the descendants and the ancestors of a node by creating an index on the elements of the ancestors field. This makes Array of Ancestors a good choice for working with subtrees. The Array of Ancestors pattern is slightly slower than the Materialized Paths pattern but is more straightforward to use. Model Tree Structures with Materialized Paths in addition to the tree node, document stores as a string the id(s) of the node’s ancestors or path. Although the Materialized Paths pattern requires additional steps of working with strings and regular expressions, the pattern also provides more flexibility in working with the path, such as finding nodes by partial paths. db.categories.insert( { _id: "Books", path: null } ) db.categories.insert( { _id: "Programming", path: ",Books," } ) db.categories.insert( { _id: "Databases", path: ",Books,Programming," } ) db.categories.insert( { _id: "Languages", path: ",Books,Programming," } ) db.categories.insert( { _id: "MongoDB", path: ",Books,Programming,Databases," } ) db.categories.insert( { _id: "dbm", path: ",Books,Programming,Databases," } ) You can query to retrieve the whole tree, sorting by the field path: db.categories.find().sort( { path: 1 } ) You can use regular expressions on the path field to find the descendants of Programming: db.categories.find( { path: /,Programming,/ } ) You can also retrieve the descendants of Books where the Books is also at the topmost level of the hierarchy: db.categories.find( { path: /^,Books,/ } ) To create an index on the field path use the following invocation: db.categories.ensureIndex( { path: 1 } ) This index may improve performance depending on the query: For queries of the Books sub-tree (e.g. /^,Books,/) an index on the path field improves the query performance significantly. For queries of the Programming sub-tree (e.g. /,Programming,/), or similar queries of sub-tress, where the node might be in the middle of the indexed string, the query must inspect the entire index. For these queries an index may provide some performance improvement if the index is significantly smaller than the entire collection. Model Tree Structures with Nested Sets The Nested Sets pattern identifies each node in the tree as stops in a round-trip traversal of the tree. The application visits each node in the tree twice; first during the initial trip, and second during the return trip. The Nested Sets pattern stores each tree node in a document; in addition to the tree node, document stores the id of node’s parent, the node’s initial stop in the left field, and its return stop in the right field. db.categories.insert( { _id: "Books", parent: 0, left: 1, right: 12 } )
db.categories.insert( { _id: "Programming", parent: "Books", left: 2, right: 11 } ) db.categories.insert( { _id: "Languages", parent: "Programming", left: 3, right: 4 } ) db.categories.insert( { _id: "Databases", parent: "Programming", left: 5, right: 10 } ) db.categories.insert( { _id: "MongoDB", parent: "Databases", left: 6, right: 7 } ) db.categories.insert( { _id: "dbm", parent: "Databases", left: 8, right: 9 } ) You can query to retrieve the descendants of a node: var databaseCategory = db.categories.findOne( { _id: "Databases" } );
db.categories.find( { left: { $gt: databaseCategory.left }, right: { $lt: databaseCategory.right } } ); The Nested Sets pattern provides a fast and efficient solution for finding subtrees but is inefficient for modifying the tree structure. As such, this pattern is best for static trees that do not change. |