Repository: cloudant/couchbackup
Pull request #287 (2019-08-08 12:47:24)

Preserve document revisions in shallow backup.
<!--
Thanks for your hard work, please ensure all items are complete before opening.
-->
## Checklist

- [x] Tick to sign-off your agreement to the [Developer Certificate of Origin (DCO) 1.1](../blob/master/DCO1.1.txt)
- [x] Added tests for code changes _or_ test/build only changes
- [x] Updated the change log file (`CHANGES.md`|`CHANGELOG.md`) _or_ test/build only changes
- [x] Completed the PR template below:

## Description
Preserve document revisions in shallow backup.
<!--
Provide a short description; saving the detail for the `Approach` section

Also EITHER:
Link to issue this PR is resolving, use the Fixes #nnn form so that the
issue closes automatically when the PR merges e.g.:

Fixes #23

OR

For PRs without an associated issue and/or test/build issues

### 1. Steps to reproduce and the simplest code sample possible to demonstrate the issue
### 2. What you expected to happen
### 3. What actually happened
-->

## Approach
Don't remove `_rev` from shallow backup file.
<!--
Be brief: which component(s) of the code base does the fix focus on.

A place to note whether the part of the code base that is being worked is
particularly sensitive.
-->

## Schema & API Changes
No change.
<!--
EITHER:

- "No change"

OR

For public API (as opposed to internal) changes

- "Fixing bug in API, will change x in such-and-such way"
-->

## Security and Privacy
No change.

<!--
EITHER:

- "No change"

OR

"Making changes in e.g. auth|https|encryption|io
need to be careful about..."

-->

## Testing
Updated testing fixture.

<!--
EITHER:

- Added new tests:
    - test x
    - test y
    - test z

OR

- Modified existing tests because ...

OR

- N/A build or packaging only changes

OR

In exceptional circumstances there may be a good reason we can't add automated
tests, for example if a specific device is required to reproduce a problem.

- No new tests because...
-->

## Monitoring and Logging
No change.
<!--
EITHER:

- "No change"

OR

- "Added new log line X..."
-->



Patch:
diff --git a/CHANGES.md b/CHANGES.md
index daee57d..8a9863c 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,7 @@
+# UNRELEASED
+
+- [FIXED] Preserve document revisions in shallow backup.
+
 # 2.4.1 (2019-06-18)
 
 - [FIXED] Removed inadvertent npm-cli-login dependency.
diff --git a/examples/s3-backup-file.js b/examples/s3-backup-file.js
index efb5eb3..ff9c7b5 100644
--- a/examples/s3-backup-file.js
+++ b/examples/s3-backup-file.js
@@ -38,11 +38,11 @@ function main() {
     .usage('Usage: $0 [options]')
     .example('$0 -s https://user:pass@host/db -b <bucket>', 'Backup db to bucket')
     .options({
-      'source': { alias: 's', nargs: 1, demandOption: true, describe: 'Source database URL' },
-      'bucket': { alias: 'b', nargs: 1, demandOption: true, describe: 'Destination bucket' },
-      'prefix': { alias: 'p', nargs: 1, describe: 'Prefix for backup object key', default: 'couchbackup' },
-      's3url': { nargs: 1, describe: 'S3 endpoint URL' },
-      'awsprofile': { nargs: 1, describe: 'The profile section to use in the ~/.aws/credentials file', default: 'default' }
+      source: { alias: 's', nargs: 1, demandOption: true, describe: 'Source database URL' },
+      bucket: { alias: 'b', nargs: 1, demandOption: true, describe: 'Destination bucket' },
+      prefix: { alias: 'p', nargs: 1, describe: 'Prefix for backup object key', default: 'couchbackup' },
+      s3url: { nargs: 1, describe: 'S3 endpoint URL' },
+      awsprofile: { nargs: 1, describe: 'The profile section to use in the ~/.aws/credentials file', default: 'default' }
     })
     .help('h').alias('h', 'help')
     .epilog('Copyright (C) IBM 2017')
diff --git a/examples/s3-backup-stream.js b/examples/s3-backup-stream.js
index 12af83b..e022026 100644
--- a/examples/s3-backup-stream.js
+++ b/examples/s3-backup-stream.js
@@ -36,11 +36,11 @@ function main() {
     .usage('Usage: $0 [options]')
     .example('$0 -s https://user:pass@host/db -b <bucket>', 'Backup db to bucket')
     .options({
-      'source': { alias: 's', nargs: 1, demandOption: true, describe: 'Source database URL' },
-      'bucket': { alias: 'b', nargs: 1, demandOption: true, describe: 'Destination bucket' },
-      'prefix': { alias: 'p', nargs: 1, describe: 'Prefix for backup object key', default: 'couchbackup' },
-      's3url': { nargs: 1, describe: 'S3 endpoint URL' },
-      'awsprofile': { nargs: 1, describe: 'The profile section to use in the ~/.aws/credentials file', default: 'default' }
+      source: { alias: 's', nargs: 1, demandOption: true, describe: 'Source database URL' },
+      bucket: { alias: 'b', nargs: 1, demandOption: true, describe: 'Destination bucket' },
+      prefix: { alias: 'p', nargs: 1, describe: 'Prefix for backup object key', default: 'couchbackup' },
+      s3url: { nargs: 1, describe: 'S3 endpoint URL' },
+      awsprofile: { nargs: 1, describe: 'The profile section to use in the ~/.aws/credentials file', default: 'default' }
     })
     .help('h').alias('h', 'help')
     .epilog('Copyright (C) IBM 2017')
diff --git a/includes/error.js b/includes/error.js
index 445679a..b8e2f6b 100644
--- a/includes/error.js
+++ b/includes/error.js
@@ -15,17 +15,17 @@
 
 // fatal errors
 const codes = {
-  'Error': 1,
-  'InvalidOption': 2,
-  'DatabaseNotFound': 10,
-  'Unauthorized': 11,
-  'Forbidden': 12,
-  'NoLogFileName': 20,
-  'LogDoesNotExist': 21,
-  'IncompleteChangesInLogFile': 22,
-  'SpoolChangesError': 30,
-  'HTTPFatalError': 40,
-  'BulkGetError': 50
+  Error: 1,
+  InvalidOption: 2,
+  DatabaseNotFound: 10,
+  Unauthorized: 11,
+  Forbidden: 12,
+  NoLogFileName: 20,
+  LogDoesNotExist: 21,
+  IncompleteChangesInLogFile: 22,
+  SpoolChangesError: 30,
+  HTTPFatalError: 40,
+  BulkGetError: 50
 };
 
 class BackupError extends Error {
diff --git a/includes/shallowbackup.js b/includes/shallowbackup.js
index 225479d..187c6fb 100644
--- a/includes/shallowbackup.js
+++ b/includes/shallowbackup.js
@@ -55,7 +55,6 @@ module.exports = function(db, options) {
 
           var docs = [];
           body.rows.forEach(function(doc) {
-            delete doc.doc._rev;
             docs.push(doc.doc);
           });
 
diff --git a/package-lock.json b/package-lock.json
index bf48cc6..4949bc0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -33,9 +33,9 @@
       }
     },
     "@babel/parser": {
-      "version": "7.4.5",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.5.tgz",
-      "integrity": "sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==",
+      "version": "7.5.5",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.5.5.tgz",
+      "integrity": "sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g==",
       "dev": true
     },
     "@cloudant/cloudant": {
@@ -375,12 +375,12 @@
       "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
     },
     "catharsis": {
-      "version": "0.8.10",
-      "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.10.tgz",
-      "integrity": "sha512-l2OUaz/3PU3MZylspVFJvwHCVfWyvcduPq4lv3AzZ2pJzZCo7kNKFNyatwujD7XgvGkNAE/Jhhbh2uARNwNkfw==",
+      "version": "0.8.11",
+      "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.11.tgz",
+      "integrity": "sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g==",
       "dev": true,
       "requires": {
-        "lodash": "^4.17.11"
+        "lodash": "^4.17.14"
       }
     },
     "chai": {
@@ -835,9 +835,9 @@
           "dev": true
         },
         "lodash": {
-          "version": "4.17.11",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
-          "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+          "version": "4.17.15",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
           "dev": true
         },
         "regexpp": {
@@ -1693,9 +1693,9 @@
           }
         },
         "lodash": {
-          "version": "4.17.11",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
-          "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+          "version": "4.17.15",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
           "dev": true
         },
         "strip-ansi": {
@@ -1878,22 +1878,22 @@
       "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
     },
     "jsdoc": {
-      "version": "3.6.2",
-      "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.2.tgz",
-      "integrity": "sha512-S2vzg99C5+gb7FWlrK4TVdyzVPGGkdvpDkCEJH1JABi2PKzPeLu5/zZffcJUifgWUJqXWl41Hoc+MmuM2GukIg==",
+      "version": "3.6.3",
+      "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.3.tgz",
+      "integrity": "sha512-Yf1ZKA3r9nvtMWHO1kEuMZTlHOF8uoQ0vyo5eH7SQy5YeIiHM+B0DgKnn+X6y6KDYZcF7G2SPkKF+JORCXWE/A==",
       "dev": true,
       "requires": {
         "@babel/parser": "^7.4.4",
         "bluebird": "^3.5.4",
-        "catharsis": "^0.8.10",
+        "catharsis": "^0.8.11",
         "escape-string-regexp": "^2.0.0",
         "js2xmlparser": "^4.0.0",
         "klaw": "^3.0.0",
         "markdown-it": "^8.4.2",
         "markdown-it-anchor": "^5.0.2",
-        "marked": "^0.6.2",
+        "marked": "^0.7.0",
         "mkdirp": "^0.5.1",
-        "requizzle": "^0.2.2",
+        "requizzle": "^0.2.3",
         "strip-json-comments": "^3.0.1",
         "taffydb": "2.6.2",
         "underscore": "~1.9.1"
@@ -1984,9 +1984,9 @@
       }
     },
     "linkify-it": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.1.0.tgz",
-      "integrity": "sha512-4REs8/062kV2DSHxNfq5183zrqXMl7WP0WzABH9IeJI+NLm429FgE1PDecltYfnOoFDFlZGh2T8PfZn0r+GTRg==",
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
+      "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
       "dev": true,
       "requires": {
         "uc.micro": "^1.0.1"
@@ -2028,9 +2028,9 @@
       "integrity": "sha1-Jjj8OaAzHpysGgS3F5mTHJxQ33k="
     },
     "lodash": {
-      "version": "4.17.11",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
-      "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
     },
     "log-symbols": {
       "version": "2.2.0",
@@ -2089,9 +2089,9 @@
       "dev": true
     },
     "marked": {
-      "version": "0.6.2",
-      "resolved": "https://registry.npmjs.org/marked/-/marked-0.6.2.tgz",
-      "integrity": "sha512-LqxwVH3P/rqKX4EKGz7+c2G9r98WeM/SW34ybhgNGhUQNKtf1GmmSkJ6cDGJ/t6tiyae49qRkpyTw2B9HOrgUA==",
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz",
+      "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==",
       "dev": true
     },
     "mdurl": {
@@ -3058,12 +3058,12 @@
       "dev": true
     },
     "requizzle": {
-      "version": "0.2.2",
-      "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.2.tgz",
-      "integrity": "sha512-oJ6y7JcUJkblRGhMByGNcszeLgU0qDxNKFCiUZR1XyzHyVsev+Mxb1tyygxLd1ORsKee1SA5BInFdUwY64GE/A==",
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz",
+      "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==",
       "dev": true,
       "requires": {
-        "lodash": "^4.17.11"
+        "lodash": "^4.17.14"
       }
     },
     "resolve": {
@@ -3589,9 +3589,9 @@
           "dev": true
         },
         "lodash": {
-          "version": "4.17.11",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
-          "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+          "version": "4.17.15",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
           "dev": true
         },
         "slice-ansi": {
diff --git a/package.json b/package.json
index 2d4fe99..8f6cbb5 100644
--- a/package.json
+++ b/package.json
@@ -34,7 +34,6 @@
   "devDependencies": {
     "eslint": "^5.15.1",
     "eslint-config-semistandard": "^14.0.0",
-    "eslint-config-standard": "^12.0.0",
     "eslint-config-standard": "^13.0.1",
     "eslint-plugin-header": "^2.0.0",
     "eslint-plugin-import": "^2.8.0",
@@ -43,7 +42,7 @@
     "eslint-plugin-react": "^7.14.2",
     "eslint-plugin-standard": "^4.0.0",
     "http-proxy": "^1.16.2",
-    "jsdoc": "^3.6.2",
+    "jsdoc": "^3.6.3",
     "mocha": "^6.1.4",
     "nock": "^10.0.0",
     "rewire": "^4.0.0",


Test patch:
diff --git a/test/citestutils.js b/test/citestutils.js
index 58a6568..f400600 100644
--- a/test/citestutils.js
+++ b/test/citestutils.js
@@ -55,7 +55,7 @@ function testBackup(params, databaseName, outputStream, callback) {
       backupStream.pipe(outputStream);
     } else {
       // Spawn process for gzip
-      gzip = spawn('gzip', [], { 'stdio': ['pipe', 'pipe', 'inherit'] });
+      gzip = spawn('gzip', [], { stdio: ['pipe', 'pipe', 'inherit'] });
       // Pipe the streams as needed
       gzip.stdout.pipe(outputStream);
       backupStream = gzip.stdin;
@@ -73,7 +73,7 @@ function testBackup(params, databaseName, outputStream, callback) {
       callback(new Error('Not implemented: cannot test encrypted API backups at this time.'));
     } else {
       // Spawn process for openssl
-      openssl = spawn('openssl', ['aes-128-cbc', '-pass', 'pass:12345'], { 'stdio': ['pipe', 'pipe', 'inherit'] });
+      openssl = spawn('openssl', ['aes-128-cbc', '-pass', 'pass:12345'], { stdio: ['pipe', 'pipe', 'inherit'] });
       // Pipe the streams as needed
       openssl.stdout.pipe(outputStream);
       backupStream = openssl.stdin;
@@ -94,7 +94,7 @@ function testBackup(params, databaseName, outputStream, callback) {
     // Use tail to watch the log file for a batch to be completed then abort
     tail = new Tail(params.opts.log, { useWatchFile: true, fsWatchOptions: { interval: 500 }, follow: false });
     tail.on('line', function(data) {
-      let matches = data.match(/:d batch\d+/);
+      const matches = data.match(/:d batch\d+/);
       if (matches !== null) {
         // Turn off the tail.
         tail.unwatch();
@@ -165,7 +165,7 @@ function testBackup(params, databaseName, outputStream, callback) {
     }
 
     // Note use spawn not fork for stdio options not supported with fork in Node 4.x
-    backup = spawn('node', args, { 'stdio': ['ignore', destination, 'pipe'] });
+    backup = spawn('node', args, { stdio: ['ignore', destination, 'pipe'] });
     // Pipe the stdout to the supplied outputStream
     if (destination === 'pipe') {
       backup.stdout.pipe(backupStream);
@@ -246,7 +246,7 @@ function testRestore(params, inputStream, databaseName, callback) {
       inputStream.pipe(restoreStream);
     } else {
       // Spawn process for gunzip
-      const gunzip = spawn('gunzip', [], { 'stdio': ['pipe', 'pipe', 'inherit'] });
+      const gunzip = spawn('gunzip', [], { stdio: ['pipe', 'pipe', 'inherit'] });
       // Pipe the streams as needed
       inputStream.pipe(gunzip.stdin);
       restoreStream = gunzip.stdout;
@@ -259,7 +259,7 @@ function testRestore(params, inputStream, databaseName, callback) {
       callback(new Error('Not implemented: cannot test encrypted API backups at this time.'));
     } else {
       // Spawn process for openssl
-      const dopenssl = spawn('openssl', ['aes-128-cbc', '-d', '-pass', 'pass:12345'], { 'stdio': ['pipe', 'pipe', 'inherit'] });
+      const dopenssl = spawn('openssl', ['aes-128-cbc', '-d', '-pass', 'pass:12345'], { stdio: ['pipe', 'pipe', 'inherit'] });
       // Pipe the streams as needed
       inputStream.pipe(dopenssl.stdin);
       restoreStream = dopenssl.stdout;
@@ -307,7 +307,7 @@ function testRestore(params, inputStream, databaseName, callback) {
     }
 
     // Note use spawn not fork for stdio options not supported with fork in Node 4.x
-    const restore = spawn('node', args, { 'stdio': ['pipe', 'inherit', 'inherit'] });
+    const restore = spawn('node', args, { stdio: ['pipe', 'inherit', 'inherit'] });
     // Pipe to write the readable inputStream into stdin
     restoreStream.pipe(restore.stdin);
     restore.stdin.on('error', function(err) {
@@ -408,7 +408,7 @@ function assertResumedBackup(params, resumedBackup, restoreCallback) {
     // For the CLI case we need to see the output because we don't have
     // the finished event.
     const listener = function(data) {
-      let matches = data.toString().match(/.*Finished - Total document revisions written: (\d+).*/);
+      const matches = data.toString().match(/.*Finished - Total document revisions written: (\d+).*/);
       if (matches !== null) {
         assertWrittenFewerThan(matches[1], params.exclusiveMaxExpected, restoreCallback);
         resumedBackup.stderr.removeListener('data', listener);
@@ -470,7 +470,7 @@ function testBackupAbortResumeRestore(params, srcDb, backupFile, targetDb, callb
 
 function dbCompare(db1Name, db2Name, callback) {
   const comparison = spawn(`./${process.env.DBCOMPARE_NAME}-${process.env.DBCOMPARE_VERSION}/bin/${process.env.DBCOMPARE_NAME}`,
-    [process.env.COUCH_BACKEND_URL, db1Name, process.env.COUCH_BACKEND_URL, db2Name], { 'stdio': 'inherit' });
+    [process.env.COUCH_BACKEND_URL, db1Name, process.env.COUCH_BACKEND_URL, db2Name], { stdio: 'inherit' });
   comparison.on('exit', function(code) {
     try {
       assert.strictEqual(code, 0, `The database comparison should succeed, got exit code ${code}`);
diff --git a/test/fixtures/animaldb_expected_shallow.json b/test/fixtures/animaldb_expected_shallow.json
index 2f4a277..f480da9 100644
--- a/test/fixtures/animaldb_expected_shallow.json
+++ b/test/fixtures/animaldb_expected_shallow.json
@@ -1,1 +1,1 @@
-[{"_id":"_design/views101","views":{"latin_name_jssum":{"map":"function(doc) {\n  if(doc.latin_name){\n    emit(doc.latin_name, doc.latin_name.length);\n  }\n}","reduce":"function (key, values, rereduce){\n  return sum(values);\n}"},"latin_name":{"map":"function(doc) {\n  if(doc.latin_name){\n    emit(doc.latin_name, doc.latin_name.length);\n  }\n}"},"diet_sum":{"map":"function(doc) {\n  if(doc.diet){\n    emit(doc.diet, 1);\n  }\n}","reduce":"_sum"},"diet_count":{"map":"function(doc) {\n  if(doc.diet && doc.latin_name){\n    emit(doc.diet, doc.latin_name);\n  }\n}","reduce":"_count"},"complex_count":{"map":"function(doc){\n  if(doc.class && doc.diet){\n    emit([doc.class, doc.diet], 1);\n  }\n}","reduce":"_count"},"diet":{"map":"function(doc) {\n  if(doc.diet){\n    emit(doc.diet, 1);\n  }\n}"},"complex_latin_name_count":{"map":"function(doc){\n  if(doc.latin_name){\n    emit([doc.class, doc.diet, doc.latin_name], doc.latin_name.length)\n  }\n}","reduce":"_count"},"diet_jscount":{"map":"function(doc) {\n  if(doc.diet){\n    emit(doc.diet, 1);\n  }\n}","reduce":"function (key, values, rereduce){\n  return values.length;\n}"},"latin_name_count":{"map":"function(doc) {\n  if(doc.latin_name){\n    emit(doc.latin_name, doc.latin_name.length);\n  }\n}","reduce":"_count"},"latin_name_sum":{"map":"function(doc) {\n  if(doc.latin_name){\n    emit(doc.latin_name, doc.latin_name.length);\n  }\n}","reduce":"_sum"}},"indexes":{"animals":{"index":"function(doc){\n  index(\"default\", doc._id);\n  if(doc.min_length){\n    index(\"min_length\", doc.min_length, {\"store\": \"yes\"});\n  }\n  if(doc.diet){\n    index(\"diet\", doc.diet, {\"store\": \"yes\"});\n  }\n  if (doc.latin_name){\n    index(\"latin_name\", doc.latin_name, {\"store\": \"yes\"});\n  }\n  if (doc['class']){\n    index(\"class\", doc['class'], {\"store\": \"yes\"});\n  }\n}"}}},{"_id":"aardvark","min_weight":40,"max_weight":65,"min_length":1,"max_length":2.2,"latin_name":"Orycteropus afer","wiki_page":"http://en.wikipedia.org/wiki/Aardvark","class":"mammal","diet":"omnivore"},{"_id":"badger","wiki_page":"http://en.wikipedia.org/wiki/Badger","min_weight":7,"max_weight":30,"min_length":0.6,"max_length":0.9,"latin_name":"Meles meles","class":"mammal","diet":"omnivore"},{"_id":"elephant","wiki_page":"http://en.wikipedia.org/wiki/African_elephant","min_weight":4700,"max_weight":6050,"min_length":3.2,"max_length":4,"class":"mammal","diet":"herbivore"},{"_id":"giraffe","min_weight":830,"min_length":5,"max_weight":1600,"max_length":6,"wiki_page":"http://en.wikipedia.org/wiki/Giraffe","class":"mammal","diet":"herbivore"},{"_id":"kookaburra","min_length":0.28,"max_length":0.42,"wiki_page":"http://en.wikipedia.org/wiki/Kookaburra","class":"bird","diet":"carnivore","latin_name":"Dacelo novaeguineae"},{"_id":"lemur","wiki_page":"http://en.wikipedia.org/wiki/Ring-tailed_lemur","min_weight":2.2,"max_weight":2.2,"min_length":0.95,"max_length":1.1,"class":"mammal","diet":"omnivore"},{"_id":"llama","min_weight":130,"max_weight":200,"min_length":1.7,"max_length":1.8,"latin_name":"Lama glama","wiki_page":"http://en.wikipedia.org/wiki/Llama","class":"mammal","diet":"herbivore"},{"_id":"panda","wiki_page":"http://en.wikipedia.org/wiki/Panda","min_weight":75,"max_weight":115,"min_length":1.2,"max_length":1.8,"class":"mammal","diet":"carnivore"},{"_id":"snipe","min_weight":0.08,"max_weight":0.14,"min_length":0.25,"max_length":0.27,"latin_name":"Gallinago gallinago","wiki_page":"http://en.wikipedia.org/wiki/Common_Snipe","class":"bird","diet":"omnivore"},{"_id":"zebra","wiki_page":"http://en.wikipedia.org/wiki/Plains_zebra","min_length":2,"max_length":2.5,"min_weight":175,"max_weight":387,"class":"mammal","diet":"herbivore"}]
+[{"_id":"_design/views101","_rev":"1-a918dd4f11704143b535f0ab3af4bf75","views":{"latin_name_jssum":{"map":"function(doc) {\n  if(doc.latin_name){\n    emit(doc.latin_name, doc.latin_name.length);\n  }\n}","reduce":"function (key, values, rereduce){\n  return sum(values);\n}"},"latin_name":{"map":"function(doc) {\n  if(doc.latin_name){\n    emit(doc.latin_name, doc.latin_name.length);\n  }\n}"},"diet_sum":{"map":"function(doc) {\n  if(doc.diet){\n    emit(doc.diet, 1);\n  }\n}","reduce":"_sum"},"diet_count":{"map":"function(doc) {\n  if(doc.diet && doc.latin_name){\n    emit(doc.diet, doc.latin_name);\n  }\n}","reduce":"_count"},"complex_count":{"map":"function(doc){\n  if(doc.class && doc.diet){\n    emit([doc.class, doc.diet], 1);\n  }\n}","reduce":"_count"},"diet":{"map":"function(doc) {\n  if(doc.diet){\n    emit(doc.diet, 1);\n  }\n}"},"complex_latin_name_count":{"map":"function(doc){\n  if(doc.latin_name){\n    emit([doc.class, doc.diet, doc.latin_name], doc.latin_name.length)\n  }\n}","reduce":"_count"},"diet_jscount":{"map":"function(doc) {\n  if(doc.diet){\n    emit(doc.diet, 1);\n  }\n}","reduce":"function (key, values, rereduce){\n  return values.length;\n}"},"latin_name_count":{"map":"function(doc) {\n  if(doc.latin_name){\n    emit(doc.latin_name, doc.latin_name.length);\n  }\n}","reduce":"_count"},"latin_name_sum":{"map":"function(doc) {\n  if(doc.latin_name){\n    emit(doc.latin_name, doc.latin_name.length);\n  }\n}","reduce":"_sum"}},"indexes":{"animals":{"index":"function(doc){\n  index(\"default\", doc._id);\n  if(doc.min_length){\n    index(\"min_length\", doc.min_length, {\"store\": \"yes\"});\n  }\n  if(doc.diet){\n    index(\"diet\", doc.diet, {\"store\": \"yes\"});\n  }\n  if (doc.latin_name){\n    index(\"latin_name\", doc.latin_name, {\"store\": \"yes\"});\n  }\n  if (doc['class']){\n    index(\"class\", doc['class'], {\"store\": \"yes\"});\n  }\n}"}}},{"_id":"aardvark","_rev":"3-fe45a3e06244adbe7ba145e74e57aba5","min_weight":40,"max_weight":65,"min_length":1,"max_length":2.2,"latin_name":"Orycteropus afer","wiki_page":"http://en.wikipedia.org/wiki/Aardvark","class":"mammal","diet":"omnivore"},{"_id":"badger","_rev":"4-51aa94e4b0ef37271082033bba52b850","wiki_page":"http://en.wikipedia.org/wiki/Badger","min_weight":7,"max_weight":30,"min_length":0.6,"max_length":0.9,"latin_name":"Meles meles","class":"mammal","diet":"omnivore"},{"_id":"elephant","_rev":"3-f812228f45b5f4e496250556195372b2","wiki_page":"http://en.wikipedia.org/wiki/African_elephant","min_weight":4700,"max_weight":6050,"min_length":3.2,"max_length":4,"class":"mammal","diet":"herbivore"},{"_id":"giraffe","_rev":"3-7665c3e66315ff40616cceef62886bd8","min_weight":830,"min_length":5,"max_weight":1600,"max_length":6,"wiki_page":"http://en.wikipedia.org/wiki/Giraffe","class":"mammal","diet":"herbivore"},{"_id":"kookaburra","_rev":"4-6038cf35dfe1211f85484dec951142c7","min_length":0.28,"max_length":0.42,"wiki_page":"http://en.wikipedia.org/wiki/Kookaburra","class":"bird","diet":"carnivore","latin_name":"Dacelo novaeguineae"},{"_id":"lemur","_rev":"3-552d9dbf91fa914a07756e69b9ceaafa","wiki_page":"http://en.wikipedia.org/wiki/Ring-tailed_lemur","min_weight":2.2,"max_weight":2.2,"min_length":0.95,"max_length":1.1,"class":"mammal","diet":"omnivore"},{"_id":"llama","_rev":"4-631ea89ca94b23a3093c1ef7dfce10e0","min_weight":130,"max_weight":200,"min_length":1.7,"max_length":1.8,"latin_name":"Lama glama","wiki_page":"http://en.wikipedia.org/wiki/Llama","class":"mammal","diet":"herbivore"},{"_id":"panda","_rev":"2-f578490963b0bd266f6c5bbf92302977","wiki_page":"http://en.wikipedia.org/wiki/Panda","min_weight":75,"max_weight":115,"min_length":1.2,"max_length":1.8,"class":"mammal","diet":"carnivore"},{"_id":"snipe","_rev":"3-4b2fb3b7d6a226b13951612d6ca15a6b","min_weight":0.08,"max_weight":0.14,"min_length":0.25,"max_length":0.27,"latin_name":"Gallinago gallinago","wiki_page":"http://en.wikipedia.org/wiki/Common_Snipe","class":"bird","diet":"omnivore"},{"_id":"zebra","_rev":"3-750dac460a6cc41e6999f8943b8e603e","wiki_page":"http://en.wikipedia.org/wiki/Plains_zebra","min_length":2,"max_length":2.5,"min_weight":175,"max_weight":387,"class":"mammal","diet":"herbivore"}]
diff --git a/test/logfilegetbatches.js b/test/logfilegetbatches.js
index b17106e..89320af 100644
--- a/test/logfilegetbatches.js
+++ b/test/logfilegetbatches.js
@@ -23,9 +23,9 @@ describe('#unit Fetching batches from a log file', function() {
     logfilegetbatches('./test/fixtures/test.log', [1, 4], function(err, data) {
       assert.strictEqual(typeof data, 'object');
       assert.strictEqual(Object.keys(data).length, 2);
-      assert.deepStrictEqual(data['1'].docs, [{ 'id': '6' }, { 'id': '7' }, { 'id': '8' }, { 'id': '9' }, { 'id': '10' }]);
+      assert.deepStrictEqual(data['1'].docs, [{ id: '6' }, { id: '7' }, { id: '8' }, { id: '9' }, { id: '10' }]);
       assert.strictEqual(data['1'].batch, 1);
-      assert.deepStrictEqual(data['4'].docs, [{ 'id': '21' }, { 'id': '22' }]);
+      assert.deepStrictEqual(data['4'].docs, [{ id: '21' }, { id: '22' }]);
       assert.strictEqual(data['4'].batch, 4);
       done();
     });