refactor
diff --git a/lib/adapters/idb.js b/lib/adapters/idb.js
index 1ce2e1c..e6783a0 100644
--- a/lib/adapters/idb.js
+++ b/lib/adapters/idb.js
@@ -219,61 +219,64 @@
       txn.objectStore(META_STORE).put(meta);
     }
 
+    function checkDoneWritingDocs() {
+      if (++numDocsWritten === docInfos.length) {
+        txn.objectStore(META_STORE).get(META_STORE).onsuccess = writeMetaData;
+      }
+    }
+
     function processDocs() {
       if (!docInfos.length) {
         return;
       }
 
-      var idsToDocInfos = new utils.Map();
+      var idsToDocs = new utils.Map();
 
-      docInfos.forEach(function (currentDoc, i) {
+      docInfos.forEach(function (currentDoc, resultsIdx) {
         if (currentDoc._id && utils.isLocalId(currentDoc._id)) {
           api[currentDoc._deleted ? '_removeLocal' : '_putLocal'](
               currentDoc, {ctx: txn}, function (err, resp) {
             if (err) {
-              results[i] = err;
+              results[resultsIdx] = err;
             } else {
-              results[i] = {};
+              results[resultsIdx] = {};
             }
-            checkDone();
+            checkDoneWritingDocs();
           });
           return;
         }
 
         var id = currentDoc.metadata.id;
-
-        var arr;
-        if (idsToDocInfos.has(id)) {
-          arr = idsToDocInfos.get(id);
+        if (idsToDocs.has(id)) {
+          idsToDocs.get(id).push([currentDoc, resultsIdx]);
         } else {
-          arr = [];
-          idsToDocInfos.set(id, arr);
+          idsToDocs.set(id, [[currentDoc, resultsIdx]]);
         }
-        arr.push([currentDoc, i]);
       });
 
-      idsToDocInfos.forEach(function (arr, id) {
+      // in the case of new_edits, the user can provide multiple docs
+      // with the same id. these need to be processed sequentially
+      idsToDocs.forEach(function (docs, id) {
         var numDone = 0;
 
-        function checkArrDone() {
-          checkDone();
-          if (++numDone < arr.length) {
-            next();
+        function docWritten() {
+          checkDoneWritingDocs();
+          if (++numDone < docs.length) {
+            nextDoc();
           }
         }
-        function next() {
-          var value = arr[numDone];
+        function nextDoc() {
+          var value = docs[numDone];
           var currentDoc = value[0];
-          var i = value[1];
+          var resultsIdx = value[1];
 
           if (fetchedDocs.has(id)) {
-            // if newEdits=false, can re-use the same id from this batch
-            return updateDoc(fetchedDocs.get(id), currentDoc, i, checkArrDone);
+            updateDoc(fetchedDocs.get(id), currentDoc, resultsIdx, docWritten);
           } else {
-            insertDoc(currentDoc, i, checkArrDone);
+            insertDoc(currentDoc, resultsIdx, docWritten);
           }
         }
-        next();
+        nextDoc();
       });
     }
 
@@ -409,7 +412,7 @@
       }
     }
 
-    function writeDoc(docInfo, winningRev, deleted, callback, i) {
+    function writeDoc(docInfo, winningRev, deleted, callback, resultsIdx) {
       var err = null;
       var recv = 0;
       docInfo.data._id = docInfo.metadata.id;
@@ -467,7 +470,7 @@
           metaDataReq.onsuccess = function () {
             delete metadata.deletedOrLocal;
             delete metadata.winningRev;
-            results[i] = docInfo;
+            results[resultsIdx] = docInfo;
             fetchedDocs.set(docInfo.metadata.id, docInfo.metadata);
             utils.call(callback);
           };
@@ -494,7 +497,7 @@
       }
     }
 
-    function updateDoc(oldDoc, docInfo, i, callback) {
+    function updateDoc(oldDoc, docInfo, resultsIdx, callback) {
       var merged =
         merge.merge(oldDoc.rev_tree, docInfo.metadata.rev_tree[0], 1000);
       var wasPreviouslyDeleted = utils.isDeleted(oldDoc);
@@ -503,7 +506,7 @@
         (!wasPreviouslyDeleted && newEdits && merged.conflicts !== 'new_leaf');
 
       if (inConflict) {
-        results[i] = makeErr(errors.REV_CONFLICT, docInfo._bulk_seq);
+        results[resultsIdx] = makeErr(errors.REV_CONFLICT, docInfo._bulk_seq);
         return callback();
       }
 
@@ -513,25 +516,19 @@
       var winningRev = merge.winningRev(docInfo.metadata);
       deleted = utils.isDeleted(docInfo.metadata, winningRev);
 
-      writeDoc(docInfo, winningRev, deleted, callback, i);
+      writeDoc(docInfo, winningRev, deleted, callback, resultsIdx);
     }
 
-    function insertDoc(docInfo, i, callback) {
+    function insertDoc(docInfo, resultsIdx, callback) {
       var winningRev = merge.winningRev(docInfo.metadata);
       var deleted = utils.isDeleted(docInfo.metadata, winningRev);
       // Cant insert new deleted documents
       if ('was_delete' in opts && deleted) {
-        results[i] = errors.MISSING_DOC;
+        results[resultsIdx] = errors.MISSING_DOC;
         return callback();
       }
 
-      writeDoc(docInfo, winningRev, deleted, callback, i);
-    }
-
-    function checkDone() {
-      if (++numDocsWritten === docInfos.length) {
-        txn.objectStore(META_STORE).get(META_STORE).onsuccess = writeMetaData;
-      }
+      writeDoc(docInfo, winningRev, deleted, callback, resultsIdx);
     }
 
     // Insert sequence number into the error so we can sort later
diff --git a/lib/adapters/websql.js b/lib/adapters/websql.js
index 996d525..4c6f8ad 100644
--- a/lib/adapters/websql.js
+++ b/lib/adapters/websql.js
@@ -573,7 +573,8 @@
       }
     }
 
-    function writeDoc(docInfo, winningRev, deleted, callback, isUpdate, i) {
+    function writeDoc(docInfo, winningRev, deleted, callback, isUpdate,
+                      resultsIdx) {
 
       function finish() {
         updateSeq++;
@@ -668,14 +669,14 @@
           [metadataStr, winningRev, id] :
           [id, seq, metadataStr];
         tx.executeSql(sql, params, function () {
-          results[i] = docInfo;
+          results[resultsIdx] = docInfo;
           fetchedDocs.set(id, docInfo.metadata);
           callback();
         });
       }
     }
 
-    function updateDoc(oldDoc, docInfo, i, callback) {
+    function updateDoc(oldDoc, docInfo, resultsIdx, callback) {
       var merged =
         merge.merge(oldDoc.rev_tree, docInfo.metadata.rev_tree[0], 1000);
       var deleted = utils.isDeleted(docInfo.metadata);
@@ -683,7 +684,7 @@
       var inConflict = (oldDocDeleted && deleted && newEdits) ||
         (!oldDocDeleted && newEdits && merged.conflicts !== 'new_leaf');
       if (inConflict) {
-        results[i] = makeErr(errors.REV_CONFLICT, docInfo._bulk_seq);
+        results[resultsIdx] = makeErr(errors.REV_CONFLICT, docInfo._bulk_seq);
         return callback();
       }
 
@@ -693,21 +694,21 @@
       var winningRev = merge.winningRev(docInfo.metadata);
       deleted = utils.isDeleted(docInfo.metadata, winningRev);
 
-      writeDoc(docInfo, winningRev, deleted, callback, true, i);
+      writeDoc(docInfo, winningRev, deleted, callback, true, resultsIdx);
     }
 
-    function insertDoc(docInfo, i, callback) {
+    function insertDoc(docInfo, resultsIdx, callback) {
       // Cant insert new deleted documents
       var winningRev = merge.winningRev(docInfo.metadata);
       var deleted = utils.isDeleted(docInfo.metadata, winningRev);
       if ('was_delete' in opts && deleted) {
-        results[i] = errors.MISSING_DOC;
+        results[resultsIdx] = errors.MISSING_DOC;
         return callback();
       }
-      writeDoc(docInfo, winningRev, deleted, callback, false, i);
+      writeDoc(docInfo, winningRev, deleted, callback, false, resultsIdx);
     }
 
-    function checkDone() {
+    function checkDoneWritingDocs() {
       if (++numDocsWritten === docInfos.length) {
         complete();
       }
@@ -718,63 +719,58 @@
         return complete();
       }
 
-      var idsToDocInfos = new utils.Map();
+      var idsToDocs = new utils.Map();
 
-      docInfos.forEach(function (currentDoc, i) {
+      docInfos.forEach(function (currentDoc, resultsIdx) {
 
         if (currentDoc._id && utils.isLocalId(currentDoc._id)) {
           api[currentDoc._deleted ? '_removeLocal' : '_putLocal'](
               currentDoc, {ctx: tx}, function (err, resp) {
             if (err) {
-              results[i] = err;
+              results[resultsIdx] = err;
             } else {
-              results[i] = {};
+              results[resultsIdx] = {};
             }
-            checkDone();
+            checkDoneWritingDocs();
           });
           return;
         }
 
         var id = currentDoc.metadata.id;
-
-        var arr;
-        if (idsToDocInfos.has(id)) {
-          arr = idsToDocInfos.get(id);
+        if (idsToDocs.has(id)) {
+          idsToDocs.get(id).push([currentDoc, resultsIdx]);
         } else {
-          arr = [];
-          idsToDocInfos.set(id, arr);
+          idsToDocs.set(id, [[currentDoc, resultsIdx]]);
         }
-        arr.push([currentDoc, i]);
       });
 
-      idsToDocInfos.forEach(function (arr, id) {
-
+      // in the case of new_edits, the user can provide multiple docs
+      // with the same id. these need to be processed sequentially
+      idsToDocs.forEach(function (docs, id) {
         var numDone = 0;
 
-        function checkArrDone() {
-          checkDone();
-          if (++numDone < arr.length) {
-            next();
+        function docWritten() {
+          checkDoneWritingDocs();
+          if (++numDone < docs.length) {
+            nextDoc();
           }
         }
-        function next() {
-          var value = arr[numDone];
+        function nextDoc() {
+          var value = docs[numDone];
           var currentDoc = value[0];
-          var i = value[1];
+          var resultsIdx = value[1];
 
           if (fetchedDocs.has(id)) {
-            // if newEdits=false, can re-use the same id from this batch
-            return updateDoc(fetchedDocs.get(id), currentDoc, i, checkArrDone);
+            updateDoc(fetchedDocs.get(id), currentDoc, resultsIdx, docWritten);
           } else {
-            insertDoc(currentDoc, i, checkArrDone);
+            insertDoc(currentDoc, resultsIdx, docWritten);
           }
         }
-        next();
+        nextDoc();
       });
     }
 
     function fetchExistingDocs(callback) {
-      // fetch all existing docs at once
       if (!docInfos.length) {
         return callback();
       }