mongodb 2.1.0-alpha → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/HISTORY.md +574 -429
  2. package/Makefile +2 -5
  3. package/README.md +108 -15
  4. package/conf.json +17 -13
  5. package/index.js +13 -2
  6. package/lib/admin.js +113 -47
  7. package/lib/aggregation_cursor.js +56 -28
  8. package/lib/apm.js +608 -0
  9. package/lib/bulk/common.js +7 -7
  10. package/lib/bulk/ordered.js +56 -17
  11. package/lib/bulk/unordered.js +52 -14
  12. package/lib/collection.js +671 -212
  13. package/lib/command_cursor.js +60 -32
  14. package/lib/cursor.js +313 -115
  15. package/lib/db.js +264 -105
  16. package/lib/gridfs/chunk.js +26 -29
  17. package/lib/gridfs/grid_store.js +150 -64
  18. package/lib/gridfs-stream/download.js +310 -0
  19. package/lib/gridfs-stream/index.js +335 -0
  20. package/lib/gridfs-stream/upload.js +450 -0
  21. package/lib/metadata.js +64 -0
  22. package/lib/mongo_client.js +69 -39
  23. package/lib/mongos.js +65 -20
  24. package/lib/replset.js +69 -34
  25. package/lib/server.js +35 -1
  26. package/lib/topology_base.js +22 -10
  27. package/lib/url_parser.js +111 -13
  28. package/lib/utils.js +9 -8
  29. package/mongolabs.js +427 -0
  30. package/package.json +8 -6
  31. package/t.js +68 -51
  32. package/test.js +12 -0
  33. package/test_boot/boot.sh +3 -0
  34. package/test_boot/ca.pem +49 -0
  35. package/test_boot/client.pem +48 -0
  36. package/test_boot/client_password.pem +51 -0
  37. package/test_boot/connect.js +29 -0
  38. package/test_boot/data/WiredTiger +2 -0
  39. package/test_boot/data/WiredTiger.lock +1 -0
  40. package/test_boot/data/WiredTiger.turtle +6 -0
  41. package/test_boot/data/WiredTiger.wt +0 -0
  42. package/test_boot/data/WiredTigerLAS.wt +0 -0
  43. package/test_boot/data/_mdb_catalog.wt +0 -0
  44. package/test_boot/data/collection-0-757073248613337118.wt +0 -0
  45. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-44-37Z-00000 +0 -0
  46. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-45-15Z-00000 +0 -0
  47. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-46-31Z-00000 +0 -0
  48. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-47-25Z-00000 +0 -0
  49. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-49-07Z-00000 +0 -0
  50. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-50-41Z-00000 +0 -0
  51. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-50-53Z-00000 +0 -0
  52. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-52-31Z-00000 +0 -0
  53. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-54-53Z-00000 +0 -0
  54. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-55-09Z-00000 +0 -0
  55. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-55-38Z-00000 +0 -0
  56. package/test_boot/data/index-1-757073248613337118.wt +0 -0
  57. package/test_boot/data/mongod.lock +0 -0
  58. package/test_boot/data/sizeStorer.wt +0 -0
  59. package/test_boot/data/storage.bson +0 -0
  60. package/test_boot/server_password.pem +51 -0
  61. package/.travis.yml +0 -10
  62. package/t1.js +0 -59
  63. package/wercker.yml +0 -19
package/lib/url_parser.js CHANGED
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
 
3
- var ReadPreference = require('./read_preference');
3
+ var ReadPreference = require('./read_preference'),
4
+ parser = require('url'),
5
+ f = require('util').format;
4
6
 
5
7
  module.exports = function(url, options) {
6
8
  // Ensure we have a default options object if none set
@@ -11,9 +13,85 @@ module.exports = function(url, options) {
11
13
  var query_string_part = '';
12
14
  var dbName = 'admin';
13
15
 
14
- // Must start with mongodb
15
- if(url.indexOf("mongodb://") != 0)
16
- throw Error("URL must be in the format mongodb://user:pass@host:port/dbname");
16
+ // Url parser result
17
+ var result = parser.parse(url, true);
18
+
19
+ if(result.protocol != 'mongodb:') {
20
+ throw new Error('invalid schema, expected mongodb');
21
+ }
22
+
23
+ if((result.hostname == null || result.hostname == '') && url.indexOf('.sock') == -1) {
24
+ throw new Error('no hostname or hostnames provided in connection string');
25
+ }
26
+
27
+ if(result.port == '0') {
28
+ throw new Error('invalid port (zero) with hostname');
29
+ }
30
+
31
+ if(!isNaN(parseInt(result.port, 10)) && parseInt(result.port, 10) > 65535) {
32
+ throw new Error('invalid port (larger than 65535) with hostname');
33
+ }
34
+
35
+ if(result.path
36
+ && result.path.length > 0
37
+ && result.path[0] != '/'
38
+ && url.indexOf('.sock') == -1) {
39
+ throw new Error('missing delimiting slash between hosts and options');
40
+ }
41
+
42
+ if(result.query) {
43
+ for(var name in result.query) {
44
+ if(name.indexOf(':') != -1) {
45
+ throw new Error('double colon in host identifier');
46
+ }
47
+
48
+ if(result.query[name] == '') {
49
+ throw new Error('query parameter ' + name + ' is an incomplete value pair');
50
+ }
51
+ }
52
+ }
53
+
54
+ if(result.auth) {
55
+ var parts = result.auth.split(':');
56
+ if(url.indexOf(result.auth) != -1 && parts.length > 2) {
57
+ throw new Error('Username with password containing an unescaped colon');
58
+ }
59
+
60
+ if(url.indexOf(result.auth) != -1 && result.auth.indexOf('@') != -1) {
61
+ throw new Error('Username containing an unescaped at-sign');
62
+ }
63
+ }
64
+
65
+ // Remove query
66
+ var clean = url.split('?').shift();
67
+
68
+ // Extract the list of hosts
69
+ var strings = clean.split(',');
70
+ var hosts = [];
71
+
72
+ for(var i = 0; i < strings.length; i++) {
73
+ var hostString = strings[i];
74
+
75
+ if(hostString.indexOf('mongodb') != -1) {
76
+ if(hostString.indexOf('@') != -1) {
77
+ hosts.push(hostString.split('@').pop())
78
+ } else {
79
+ hosts.push(hostString.substr('mongodb://'.length));
80
+ }
81
+ } else if(hostString.indexOf('/') != -1) {
82
+ hosts.push(hostString.split('/').shift());
83
+ } else if(hostString.indexOf('/') == -1) {
84
+ hosts.push(hostString.trim());
85
+ }
86
+ }
87
+
88
+ for(var i = 0; i < hosts.length; i++) {
89
+ var r = parser.parse(f('mongodb://%s', hosts[i].trim()));
90
+ if(r.path && r.path.indexOf(':') != -1) {
91
+ throw new Error('double colon in host identifier');
92
+ }
93
+ }
94
+
17
95
  // If we have a ? mark cut the query elements off
18
96
  if(url.indexOf("?") != -1) {
19
97
  query_string_part = url.substr(url.indexOf("?") + 1);
@@ -33,7 +111,7 @@ module.exports = function(url, options) {
33
111
  if(connection_part.indexOf(".sock/") != -1) {
34
112
  dbName = connection_part.split(".sock/")[1];
35
113
  connection_part = connection_part.split("/", connection_part.indexOf(".sock") + ".sock".length);
36
- }
114
+ }
37
115
  } else if(connection_part.indexOf("/") != -1) {
38
116
  dbName = connection_part.split("/")[1];
39
117
  connection_part = connection_part.split("/")[0];
@@ -80,6 +158,9 @@ module.exports = function(url, options) {
80
158
  } else {
81
159
  // Split up the db
82
160
  hostPart = connection_part;
161
+ // Deduplicate servers
162
+ var deduplicatedServers = {};
163
+
83
164
  // Parse all server results
84
165
  servers = hostPart.split(',').map(function(h) {
85
166
  var _host, _port, ipv6match;
@@ -95,15 +176,22 @@ module.exports = function(url, options) {
95
176
  // Check for localhost?safe=true style case
96
177
  if(_host.indexOf("?") != -1) _host = _host.split(/\?/)[0];
97
178
  }
179
+
180
+ // No entry returned for duplicate servr
181
+ if(deduplicatedServers[_host + "_" + _port]) return null;
182
+ deduplicatedServers[_host + "_" + _port] = 1;
183
+
98
184
  // Return the mapped object
99
185
  return {host: _host, port: _port};
186
+ }).filter(function(x) {
187
+ return x != null;
100
188
  });
101
189
  }
102
190
 
103
191
  // Get the db name
104
192
  object.dbName = dbName || 'admin';
105
193
  // Split up all the options
106
- urlOptions = (query_string_part || '').split(/[&;]/);
194
+ urlOptions = (query_string_part || '').split(/[&;]/);
107
195
  // Ugh, we have to figure out which options go to which constructor manually.
108
196
  urlOptions.forEach(function(opt) {
109
197
  if(!opt) return;
@@ -143,6 +231,10 @@ module.exports = function(url, options) {
143
231
  serverOptions.ssl = (value == 'true');
144
232
  replSetServersOptions.ssl = (value == 'true');
145
233
  break;
234
+ case 'sslValidate':
235
+ serverOptions.sslValidate = (value == 'true');
236
+ replSetServerOptions.sslValidate = (value == 'true');
237
+ break;
146
238
  case 'replicaSet':
147
239
  case 'rs_name':
148
240
  replSetServersOptions.rs_name = value;
@@ -170,6 +262,9 @@ module.exports = function(url, options) {
170
262
  case 'native_parser':
171
263
  dbOptions.native_parser = (value == 'true');
172
264
  break;
265
+ case 'readConcernLevel':
266
+ dbOptions.readConcern = {level: value};
267
+ break;
173
268
  case 'connectTimeoutMS':
174
269
  serverOptions.socketOptions.connectTimeoutMS = parseInt(value, 10);
175
270
  replSetServersOptions.socketOptions.connectTimeoutMS = parseInt(value, 10);
@@ -201,15 +296,16 @@ module.exports = function(url, options) {
201
296
  } else if(value == 'MONGODB-X509') {
202
297
  object.auth = {user: decodeURIComponent(authPart)};
203
298
  }
204
-
299
+
205
300
  // Only support GSSAPI or MONGODB-CR for now
206
- if(value != 'GSSAPI'
301
+ if(value != 'GSSAPI'
207
302
  && value != 'MONGODB-X509'
208
303
  && value != 'MONGODB-CR'
304
+ && value != 'DEFAULT'
209
305
  && value != 'SCRAM-SHA-1'
210
- && value != 'PLAIN')
211
- throw new Error("only GSSAPI, PLAIN, MONGODB-X509, SCRAM-SHA-1 or MONGODB-CR is supported by authMechanism");
212
-
306
+ && value != 'PLAIN')
307
+ throw new Error("only DEFAULT, GSSAPI, PLAIN, MONGODB-X509, SCRAM-SHA-1 or MONGODB-CR is supported by authMechanism");
308
+
213
309
  // Authentication mechanism
214
310
  dbOptions.authMechanism = value;
215
311
  break;
@@ -233,7 +329,7 @@ module.exports = function(url, options) {
233
329
  break;
234
330
  case 'readPreference':
235
331
  if(!ReadPreference.isValid(value)) throw new Error("readPreference must be either primary/primaryPreferred/secondary/secondaryPreferred/nearest");
236
- dbOptions.read_preference = value;
332
+ dbOptions.readPreference = value;
237
333
  break;
238
334
  case 'readPreferenceTags':
239
335
  // Decode the value
@@ -272,7 +368,9 @@ module.exports = function(url, options) {
272
368
  || dbOptions.safe == true)) throw new Error("w set to -1 or 0 cannot be combined with safe/w/journal/fsync")
273
369
 
274
370
  // If no read preference set it to primary
275
- if(!dbOptions.read_preference) dbOptions.read_preference = 'primary';
371
+ if(!dbOptions.readPreference) {
372
+ dbOptions.readPreference = 'primary';
373
+ }
276
374
 
277
375
  // Add servers to result
278
376
  object.servers = servers;
package/lib/utils.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
 
3
- var MongoError = require('mongodb-core').MongoError
3
+ var MongoError = require('mongodb-core').MongoError,
4
+ f = require('util').format;
4
5
 
5
6
  var shallowClone = function(obj) {
6
7
  var copy = {};
@@ -13,9 +14,9 @@ var getSingleProperty = function(obj, name, value) {
13
14
  Object.defineProperty(obj, name, {
14
15
  enumerable:true,
15
16
  get: function() {
16
- return value
17
+ return value
17
18
  }
18
- });
19
+ });
19
20
  }
20
21
 
21
22
  var formatSortValue = exports.formatSortValue = function(sortDirection) {
@@ -50,7 +51,7 @@ var formattedOrderClause = exports.formattedOrderClause = function(sortValue) {
50
51
  orderBy[sortValue[i]] = 1;
51
52
  } else {
52
53
  orderBy[sortValue[i][0]] = formatSortValue(sortValue[i][1]);
53
- }
54
+ }
54
55
  }
55
56
  } else if(sortValue != null && typeof sortValue == 'object') {
56
57
  orderBy = sortValue;
@@ -110,7 +111,7 @@ var toError = function(error) {
110
111
  if (error instanceof Error) return error;
111
112
 
112
113
  var msg = error.err || error.errmsg || error.errMessage || error;
113
- var e = new MongoError(msg);
114
+ var e = MongoError.create({message: msg, driver:true});
114
115
 
115
116
  // Get all object keys
116
117
  var keys = typeof error == 'object'
@@ -137,12 +138,12 @@ var normalizeHintField = function normalizeHintField(hint) {
137
138
 
138
139
  hint.forEach(function(param) {
139
140
  finalHint[param] = 1;
140
- });
141
+ });
141
142
  } else if(hint != null && typeof hint == 'object') {
142
143
  finalHint = {};
143
144
  for (var name in hint) {
144
145
  finalHint[name] = hint[name];
145
- }
146
+ }
146
147
  }
147
148
 
148
149
  return finalHint;
@@ -230,4 +231,4 @@ exports.normalizeHintField = normalizeHintField;
230
231
  exports.handleCallback = handleCallback;
231
232
  exports.decorateCommand = decorateCommand;
232
233
  exports.isObject = isObject;
233
- exports.debugOptions = debugOptions;
234
+ exports.debugOptions = debugOptions;
package/mongolabs.js ADDED
@@ -0,0 +1,427 @@
1
+ /*
2
+ * PROPRIETARY AND CONFIDENTIAL
3
+ *
4
+ * The contents of this example are proprietary and confidential, and may not be used or distributed without express
5
+ * written permission from MongoLab.
6
+ *
7
+ */
8
+
9
+ var mongodb = require("mongodb");
10
+ var async = require("async");
11
+
12
+ var ObjectId = mongodb.ObjectID;
13
+
14
+ //mongodb.Logger.setLevel("debug");
15
+ var uri = process.env.MONGODB_URI;
16
+
17
+ function log(s) {
18
+ console.log(new Date().toISOString() + " " + s);
19
+ }
20
+
21
+ log("Connecting...");
22
+ mongodb.MongoClient.connect(
23
+ uri,
24
+ {
25
+ replSet: {
26
+ //poolSize: 10
27
+ socketOptions: {
28
+ connectTimeoutMS: 60 * 1000
29
+ }
30
+ }
31
+ },
32
+ function (err, db) {
33
+ if (err) {
34
+ log("Error trying to connect.");
35
+ log(err.stack);
36
+ } else {
37
+ log("Connected.");
38
+ db.serverConfig.on('joined', function(t, s) {
39
+ log("joined :: " + t + " :: " + s.name);
40
+ });
41
+ db.serverConfig.on('left', function(t, s) {
42
+ log("joined :: " + t + " :: " + s.name);
43
+ });
44
+ db.serverConfig.on('timeout', function(err) {
45
+ log("timeout :: ");
46
+ log(err.stack);
47
+ });
48
+ log("Running aggregations...");
49
+ async.forEachOf(
50
+ aggregations,
51
+ function (item, i, cb) {
52
+ log("Running aggregation " + i + "...");
53
+ db.collection(item.collection).aggregate(item.pipeline, function (err, result) {
54
+ if (err) {
55
+ log("Error running aggregation " + i + ".");
56
+ log(err.stack)
57
+ } else {
58
+ log("Done running aggregation " + i + ".");
59
+ }
60
+ cb();
61
+ });
62
+ },
63
+ function (err) {
64
+ if (err) {
65
+ log("Untrapped error.");
66
+ log(err.stack);
67
+ } else {
68
+ log("Finished running all aggregations.")
69
+ }
70
+ log("Closing database...");
71
+ db.close();
72
+ }
73
+ )
74
+ }
75
+ }
76
+ );
77
+
78
+ var aggregations = [
79
+ // ========== 1 ==========
80
+ {
81
+ collection: "tlogs",
82
+ pipeline: [
83
+ {
84
+ "$match": {
85
+ "_type": "tlog",
86
+ "organization": ObjectId("53eb1ee2e6c77111203d8503"),
87
+ "businessDate": {
88
+ "$gte": ISODate("2015-11-01T00:00:00.000+0000"),
89
+ "$lt": ISODate("2015-11-28T23:59:59.999+0000")
90
+ }
91
+ }
92
+ },
93
+ {
94
+ "$unwind": "$order"
95
+ },
96
+ {
97
+ "$unwind": "$order.orderedOffers"
98
+ },
99
+ {
100
+ "$redact": {
101
+ "$cond": {
102
+ "if": {
103
+ "$not": "$order.orderedOffers.onTheHouse"
104
+ },
105
+ "then": "$$KEEP",
106
+ "else": "$$PRUNE"
107
+ }
108
+ }
109
+ },
110
+ {
111
+ "$redact": {
112
+ "$cond": {
113
+ "if": {
114
+ "$not": "$order.orderedOffers.cancellation"
115
+ },
116
+ "then": "$$KEEP",
117
+ "else": "$$PRUNE"
118
+ }
119
+ }
120
+ },
121
+ {
122
+ "$group": {
123
+ "_id": "$order.orderedOffers.offer",
124
+ "offer": {
125
+ "$first": "$order.orderedOffers.offer"
126
+ },
127
+ "menu": {
128
+ "$first": "$order.orderedOffers.menu"
129
+ },
130
+ "totalAmount": {
131
+ "$sum": "$order.orderedOffers.amount"
132
+ },
133
+ "totalCount": {
134
+ "$sum": NumberInt(1)
135
+ },
136
+ "totalDiners": {
137
+ "$sum": "$diners"
138
+ }
139
+ }
140
+ }
141
+ ]
142
+ },
143
+ // ========== 2 ==========
144
+ {
145
+ collection: "tlogs",
146
+ pipeline: [
147
+ {
148
+ "$match": {
149
+ "_type": "tlog",
150
+ "organization": ObjectId("53eb1ee2e6c77111203d8503"),
151
+ "businessDate": {
152
+ "$gte": ISODate("2015-11-01T00:00:00.000+0000"),
153
+ "$lt": ISODate("2015-11-28T23:59:59.999+0000")
154
+ }
155
+ }
156
+ },
157
+ {
158
+ "$unwind": "$order"
159
+ },
160
+ {
161
+ "$unwind": "$order.orderedItems"
162
+ },
163
+ {
164
+ "$redact": {
165
+ "$cond": {
166
+ "if": {
167
+ "$not": "$order.orderedItems.onTheHouse"
168
+ },
169
+ "then": "$$PRUNE",
170
+ "else": "$$KEEP"
171
+ }
172
+ }
173
+ },
174
+ {
175
+ "$group": {
176
+ "_id": {
177
+ "category": "$order.orderedItems.category"
178
+ },
179
+ "totalItems": {
180
+ "$sum": NumberInt(1)
181
+ },
182
+ "totalAmount": {
183
+ "$sum": "$order.orderedItems.price"
184
+ }
185
+ }
186
+ }
187
+ ]
188
+ },
189
+ // ========== 3 ==========
190
+ {
191
+ collection: "tlogs",
192
+ pipeline: [
193
+ {
194
+ "$match": {
195
+ "_type": "tlog",
196
+ "organization": ObjectId("53eb1ee2e6c77111203d8503"),
197
+ "businessDate": {
198
+ "$gte": ISODate("2015-11-01T00:00:00.000+0000"),
199
+ "$lt": ISODate("2015-11-28T23:59:59.999+0000")
200
+ },
201
+ "order": {
202
+ "$elemMatch": {
203
+ "onTheHouse": null
204
+ }
205
+ }
206
+ }
207
+ },
208
+ {
209
+ "$unwind": "$order"
210
+ },
211
+ {
212
+ "$unwind": "$order.tips"
213
+ },
214
+ {
215
+ "$project": {
216
+ "_id": "$order.tips._id",
217
+ "tableTip": {
218
+ "$cond": [
219
+ {
220
+ "$eq": [
221
+ {
222
+ "$size": {
223
+ "$setIntersection": [
224
+ "$order.tableIds",
225
+ [
226
+ ObjectId("53eb1ee4e6c77111203d852e"),
227
+ ObjectId("53eb1ee4e6c77111203d852f"),
228
+ ObjectId("53eb1ee4e6c77111203d8530"),
229
+ ObjectId("53eb1ee4e6c77111203d8531"),
230
+ ObjectId("53eb1ee4e6c77111203d8532"),
231
+ ObjectId("53eb1ee4e6c77111203d8533"),
232
+ ObjectId("53eb1ee4e6c77111203d8534"),
233
+ ObjectId("53eb1ee4e6c77111203d8535"),
234
+ ObjectId("53eb1ee4e6c77111203d8536"),
235
+ ObjectId("53eb1ee4e6c77111203d8537"),
236
+ ObjectId("53eb1ee4e6c77111203d8538"),
237
+ ObjectId("53eb1ee4e6c77111203d8539"),
238
+ ObjectId("53eb1ee4e6c77111203d853a"),
239
+ ObjectId("53eb1ee4e6c77111203d853b"),
240
+ ObjectId("53eb1ee4e6c77111203d853c"),
241
+ ObjectId("53eb1ee4e6c77111203d853d"),
242
+ ObjectId("53eb1ee4e6c77111203d853e"),
243
+ ObjectId("53eb1ee4e6c77111203d853f"),
244
+ ObjectId("53eb1ee4e6c77111203d8540"),
245
+ ObjectId("53eb1ee4e6c77111203d8541"),
246
+ ObjectId("53eb1ee4e6c77111203d8542"),
247
+ ObjectId("53eb1ee4e6c77111203d8543"),
248
+ ObjectId("53eb1ee4e6c77111203d8544"),
249
+ ObjectId("53eb1ee4e6c77111203d8545"),
250
+ ObjectId("53eb1ee4e6c77111203d8546"),
251
+ ObjectId("53eb1ee4e6c77111203d8547"),
252
+ ObjectId("53eb1ee4e6c77111203d8548"),
253
+ ObjectId("53eb1ee4e6c77111203d8549"),
254
+ ObjectId("53eb1ee4e6c77111203d854a"),
255
+ ObjectId("53eb1ee4e6c77111203d854b"),
256
+ ObjectId("53eb1ee4e6c77111203d854c"),
257
+ ObjectId("53eb1ee4e6c77111203d854d"),
258
+ ObjectId("53eb1ee4e6c77111203d854e"),
259
+ ObjectId("53eb1ee4e6c77111203d854f"),
260
+ ObjectId("53eb1ee4e6c77111203d8550"),
261
+ ObjectId("53eb1ee4e6c77111203d8551"),
262
+ ObjectId("53eb1ee4e6c77111203d8552"),
263
+ ObjectId("53eb1ee4e6c77111203d8553"),
264
+ ObjectId("53eb1ee4e6c77111203d8554"),
265
+ ObjectId("53eb1ee4e6c77111203d8555")
266
+ ]
267
+ ]
268
+ }
269
+ },
270
+ NumberInt(0)
271
+ ]
272
+ },
273
+ false,
274
+ true
275
+ ]
276
+ },
277
+ "amount": "$order.tips.amount"
278
+ }
279
+ },
280
+ {
281
+ "$group": {
282
+ "_id": "$tableTip",
283
+ "tableTip": {
284
+ "$first": "$tableTip"
285
+ },
286
+ "totalAmount": {
287
+ "$sum": "$amount"
288
+ },
289
+ "totalCount": {
290
+ "$sum": NumberInt(1)
291
+ }
292
+ }
293
+ }
294
+ ]
295
+ },
296
+ // ========== 4 ==========
297
+ {
298
+ collection: "tlogs",
299
+ pipeline: [
300
+ {
301
+ "$match": {
302
+ "_type": "tlog",
303
+ "organization": ObjectId("53eb1ee2e6c77111203d8503"),
304
+ "businessDate": {
305
+ "$gte": ISODate("2015-11-01T00:00:00.000+0000"),
306
+ "$lt": ISODate("2015-11-28T23:59:59.999+0000")
307
+ }
308
+ }
309
+ },
310
+ {
311
+ "$unwind": "$order"
312
+ },
313
+ {
314
+ "$group": {
315
+ "_id": {
316
+ "orderType": "$order.orderType"
317
+ },
318
+ "orderType": {
319
+ "$first": "$order.orderType"
320
+ },
321
+ "diners": {
322
+ "$sum": "$diners"
323
+ },
324
+ "totalCount": {
325
+ "$sum": NumberInt(1)
326
+ }
327
+ }
328
+ }
329
+ ]
330
+ },
331
+ // 5, 6, and 7 deleted by Akira just to reduce character count within this JIRA comment.
332
+ // ========== 8 ==========
333
+ {
334
+ collection: "tlogs",
335
+ pipeline: [
336
+ {
337
+ "$match": {
338
+ "_type": "tlog",
339
+ "organization": ObjectId("53eb1ee2e6c77111203d8503"),
340
+ "businessDate": {
341
+ "$gte": ISODate("2015-10-01T00:00:00.000+0000"),
342
+ "$lt": ISODate("2015-11-28T23:59:59.999+0000")
343
+ }
344
+ }
345
+ },
346
+ {
347
+ "$unwind": "$order"
348
+ },
349
+ {
350
+ "$unwind": "$order.orderedItems"
351
+ },
352
+ {
353
+ "$redact": {
354
+ "$cond": {
355
+ "if": {
356
+ "$and": [
357
+ {
358
+ "$not": "$order.orderedItems.cancellation"
359
+ },
360
+ {
361
+ "$not": "$order.orderedItems.onTheHouse"
362
+ }
363
+ ]
364
+ },
365
+ "then": "$$KEEP",
366
+ "else": "$$KEEP"
367
+ }
368
+ }
369
+ },
370
+ {
371
+ "$unwind": "$order.orderedItems.selectedModifiers"
372
+ },
373
+ {
374
+ "$group": {
375
+ "_id": {
376
+ "category": "$order.orderedItems.category"
377
+ },
378
+ "totalAmount": {
379
+ "$sum": "$order.orderedItems.selectedModifiers.price"
380
+ }
381
+ }
382
+ }
383
+ ]
384
+ },
385
+ // ========== 9 ==========
386
+ {
387
+ collection: "tlogs",
388
+ pipeline: [
389
+ {
390
+ "$match": {
391
+ "_type": "tlog",
392
+ "organization": ObjectId("53eb1ee2e6c77111203d8503"),
393
+ "businessDate": {
394
+ "$gte": ISODate("2015-10-01T00:00:00.000+0000"),
395
+ "$lt": ISODate("2015-11-28T23:59:59.999+0000")
396
+ },
397
+ "order.orderType": "Refund"
398
+ }
399
+ },
400
+ {
401
+ "$unwind": "$order"
402
+ },
403
+ {
404
+ "$unwind": "$order.payments"
405
+ },
406
+ {
407
+ "$group": {
408
+ "_id": null,
409
+ "totalCount": {
410
+ "$sum": NumberInt(1)
411
+ },
412
+ "totalAmount": {
413
+ "$sum": "$order.payments.amount"
414
+ }
415
+ }
416
+ }
417
+ ]
418
+ }
419
+ ];
420
+
421
+ function ISODate(x) {
422
+ return new Date(x);
423
+ }
424
+
425
+ function NumberInt(x) {
426
+ return x;
427
+ }