UNPKG

5.3 kBMarkdownView Raw
1mongopatch [![Build Status](https://travis-ci.org/e-conomic/mongopatch.png?branch=master)](https://travis-ci.org/e-conomic/mongopatch)
2==========
3
4MongoDB patching tool. Update and log mongodb documents.
5
6 npm install -g mongopatch
7
8
9Writing patches
10---------------
11
12Patches are written as separate modules, exposing a single patching function.
13
14```javascript
15
16module.exports = function(patch) {
17 // Specify which patching system version to use for this patch (required)
18 patch.version('0.1.0');
19
20 // Update all users that match the provided query.
21 // The query is optional, if not provided all the documents
22 // in the collection are processed.
23 patch.update('users', { name: 'e-conomic' }, function(document, callback) {
24 // The callback function should be called with the update to apply,
25 // this can be any valid mongodb update query.
26 callback(null, { $set: { email: 'e-conomic@e-conomic.com', associates: 'unknown' } });
27 });
28
29 // Register an after callback, to be run after each update.
30 patch.after(function(update, callback) {
31 var isValid = update.after.email === 'e-conomic@e-conomic.com';
32
33 // Call the callback function with an error to abort the patching process.
34 // Use this to guard against corrupted updates.
35 callback(isValid ? null : new Error('Update failed'));
36 });
37}
38```
39
40The after callback gets an options map, containing the `before` and `after` documents, a `modfifed` flag (telling if there any changes between the two documents) and a `diff` object (the diff between the two documents).
41
42Another example where we process all users.
43
44```javascript
45function shouldUpdate(document) {
46 // ...
47}
48
49function update(document) {
50 // ...
51}
52
53function isValid(document) {
54 // ...
55}
56
57module.exports = function(patch) {
58 patch.version('0.1.0');
59
60 // All users are processed, since no filter query provided.
61 patch.update('users', function(document, callback) {
62 if(!shouldUpdate(document)) {
63 // Calling the callback with no arguments, skips the document in the update process.
64 return callback();
65 }
66
67 update(document);
68
69 if(!isValid(document)) {
70 // Validate document before performing the actual update in the database.
71 // Passing an error as first argument, aborts the patching process,
72 // and can leave the database in inconsistent state.
73 return callback(new Error('Invalid document'));
74 }
75
76 // Apply the update, by overwritting the whole document
77 callback(null, document);
78 });
79}
80```
81
82Runing patches
83--------------
84
85Run patches using the `mongopatch` command-line tool. Basic usage:
86
87 mongopatch path/to/patch.js --db databaseConnectionString --dry-run --log-db logDatabaseConnectionString
88
89Available options (too see a full list of options, run `mongopatch` without any arguments).
90
91- **db**: MongoDB connection string (e.g. `user:password@localhost:27017/development` or `development`).
92- **log-db**: MongoDB connection string for the log database. When provided a version of the document is stored before and after the update.
93- **dry-run**: Do not perform any changes in the database. Changes are performed on copy of the documents and stored in the log db (if available).
94- **parallel**: Run the patch with given parallelism. It may run the patch faster.
95
96![mongopatch](/mongopatch.png)
97
98Running the tool, outputs the above interface, where it is possible to track progress and accumulated changes done to the documents. The diff shows how many times a property has been added, updated or removed between the original and the updated documents (note that all array changes are grouped).
99
100When running on a live database, where external changes can occur, the progress indicator may be incorrect, as documents can be added or removed. Also skipping documents in `patch.update` causes the progress to fall behind.
101
102Log Database
103------------
104
105When a log database is available, a collection is created for every patch run. A document in the patch collection, contains data about the applied update. The `before` key points to the original document, `after` to the updated document, `modified` is a boolean flag telling if there were any changes and `diff` the difference between the `before` and `after` document (if `modified` is false, this is going to be an empty object). It also includes additional meta data.
106
107```javascript
108{
109 "before": {
110 "_id": ObjectId("507d2a650ea37a02000001ae"),
111 "name": "e-conomic",
112 "associates": "debitoor"
113 },
114 "after": {
115 "_id": ObjectId("507d2a650ea37a02000001ae"),
116 "name": "e-conomic",
117 "associates": "unknown",
118 "email": "e-conomic@e-conomic.com"
119 },
120 "modified": true,
121 "diff": { // diff is a nested object, where leafs can have one of the three values added, updated, removed
122 "associates": "updated",
123 "email": "added"
124 },
125 "createdAt": ISODate("2013-12-17T15:28:14.737Z"), // when was the log document created
126 "collection": "development.users", // full collection name
127 "modifier": "{ \"$set\": { \"email\": \"e-conomic@e-conomic.com\" } }", // stringified modifier (passed to the callback in path.update)
128 "query": "{ \"name\": \"e-conomic\" }" // stringified query (passed to patch.update function)
129}
130```
131
132In some cases if an error occures during the patching, an `error` object is added to the log document, containing the error message and stack.