0

I have a collection in MongoDB from which I'd like to pull a random sample. This will be about 14,000 documents or so. I'd like every document in this random sample to be updated. What's the best/most efficient way to do this?

Here's the code I have right now, but it's lacking an update part.

db.collection(collection).aggregate([{ $sample: { size: sample_size } }]).toArray((err, docs) => {

      if (err) {
        console.log(err);
      }

      else {
        // update all 14,000 (or so) documents that were just pulled
      }
    })
Scott
  • 1,207
  • 2
  • 15
  • 38
  • Because you’ve inserted each doc into an array you can use the array.map method to apply the update operation to each update in the array. – Len Joseph Jul 15 '19 at 03:55
  • So I'd have to call the `update` method 14,000 separate times? – Scott Jul 15 '19 at 15:29
  • Update to my comment, use `forEach` instead of `map`, since `forEach` transforms the array element in-place rather than returning a new array like `map` would. Either way, yes, calling any array method to transform array data requires n array accesses, where n = array length. Array updates have O(n) time complexity, so the time it takes to update an array grows linearly as the array grows, assuming the update itself has O(1) constant time complexity. Please also see https://stackoverflow.com/questions/12482961/is-it-possible-to-change-values-of-the-array-when-doing-foreach-in-javascript – Len Joseph Jul 15 '19 at 16:31

1 Answers1

0

As mentioned in the comments, an array update can be performed using forEach to access each document in the array and make a change. For 14k elements, this is not an instant process. One option is to display a loading icon to the user while this completes. An alternative is to perform this operation when data is initially saved to the database, to avoid batch-processing upon retrieval from the database (if your use-case allows it). A third, and much more involved solution, would be to use a more efficient data structure than an array.

   db.collection(collection).aggregate([{ $sample: { size: sample_size } }]).toArray((err, docs) => {

          if (err) {
            console.log(err);
          }

          else {
            docs.forEach((doc) => {doc.vegetable = 'asparagus'});
            return docs;
          }
        })
Len Joseph
  • 1,406
  • 10
  • 21
  • Thanks but I'm looking to actually save the new field to the object in the MongoDB database. This only adds it to the resulting document in my server, doesn't save it on MongoDB. – Scott Jul 24 '19 at 23:02
  • Ahh, I thought you were working with a GET request. If you're iterating over an object prior to saving using middleware is probably a good pattern. – Len Joseph Jul 25 '19 at 01:29