This repository has been archived by the owner on Nov 29, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
extend-properties
executable file
·120 lines (99 loc) · 3.05 KB
/
extend-properties
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/env node
var path = require('path'),
_ = require('underscore');
var basePath = process.argv[1].split(path.sep),
self = basePath.pop(),
input = '',
stats = { docs: 0, updates: 0 },
index = {},
updates = {},
options = {},
tmp;
var usageInfo = `
Usage: cat data.json | ./node_modules/.bin/${self} [-ah] index.json > data-edited.json
Description:
Take a list of JSON objects with an \`_id\` property on standard input and
apply changes to it. The changes are based on an index file that is a list
of JSON objects with an \`id\` property and the other properties you want to
change.
This command is basically a wrapper around the Underscore.js \`extend\`
function and calls it like this:
newDoc = _.extend(origDoc, change);
Options:
-h This help information.
-a Update all occurrences of an object, rather than just updating the first
or top level occurrence. Be careful when using this on embedded
documents, because this can cause conflicts if the embedded document is
modified but the referenced doc is not updated. To modify embedded
documents properly you should update the source document first and then
replace the embedded document so the \`_rev\` property matches.
`;
var usage = function() {
console.error(usageInfo);
process.exit(1);
};
if (process.argv.indexOf('-a') !== -1) {
options.updateAll = true;
process.argv.splice(process.argv.indexOf('-a'), 1);
}
if (process.argv.indexOf('-h') !== -1) {
usage();
}
if (process.argv.length < 3) {
console.error('\nError: Please provide the file system path to the index.');
usage();
} else {
tmp = require(path.resolve(process.argv[2]));
tmp.forEach(function(obj) {
var id = obj.id;
delete(obj.id);
index[id] = obj;
});
}
// null is not an object
var isObject = function (obj) {
return Boolean(obj && typeof obj === 'object');
};
/*
* If the property is an object and not null continue walking, if we see an _id
* property check the index for a match and try to update its properties.
*/
var walkProperties = function(data) {
Object.keys(data).forEach(function(k) {
if (k === '_id' && index[data[k]]) {
if (updates[data[k]] && !options.updateAll) {
// only modify embedded docs when update all flag is set.
return;
}
data = _.extend(data, index[data[k]]);
updates[data[k]] = true;
stats.updates++;
} else if (data[k] && typeof data[k] === 'object') {
walkProperties(data[k]);
}
});
};
process.stdin.setEncoding('utf8');
process.stdin.on('data', function (chunk) {
input += chunk;
});
process.stdin.on('end', function () {
var data = JSON.parse(input);
if (data.docs) {
data = data.docs;
} else if (data.rows) {
data = data.rows;
} else if (!Array.isArray(data)) {
data = [data];
}
data.forEach(function(doc) {
// skip null values
if (!isObject(doc)) {
return;
}
stats.docs++;
walkProperties(doc.doc || doc);
});
process.stdout.write(JSON.stringify({docs: data}));
console.error(stats);
});