11

When doing a research in mongo shell I often write quite complex queries and want the result to be stored in other collection. I know the way to do it with .forEach():

db.documents.find(query).forEach(function(d){db.results.insert(d)})

But it's kind of tedious to write that stuff each time. Is there a cleaner way? I'd like the syntax to be something like db.documents.find(query).dumpTo('collectionName').

vorou
  • 1,869
  • 3
  • 18
  • 35

4 Answers4

12

Here's a solution I'll use: db.results.insert(db.docs.find(...).toArray())

There is still too much noise, though.

UPD: There is also an option to rewrite find using aggregation pipeline. Then you can use $out operator.

vorou
  • 1,869
  • 3
  • 18
  • 35
5

It looks like you are doing your queries from the mongo shell, which allows you to write code in javascript. You can assign the result of queries to a variable:

result = db.mycollection.findOne(my_query)

And save the result to another collection:

db.result.save(result)

You might have to remove the _id of the result if you want to append it to the result collection, to prevent a duplicate key error

Edit:

db.mycollection.findOne({'_id':db.mycollection.findOne()['_id']})
db.foo.save(db.bar.findOne(...))

If you want to save an array, you can write a javascript function. Something like the following should work (I haven't tested it):

function save_array(arr) {
    for(var i = 0; i < arr.length; i++) {
        db.result.save(arr[i])
    }
}

...

result = db.mycollection.find(...)
save_array(result)

If you want the function to be available every time you start mongo shell, you can include it in your .mongorc.js file

Mzzl
  • 3,926
  • 28
  • 39
  • Well, but I don't want to use `.forEach` at all. It would be nice if I could do `db.result.save(db.docs.find(...))`, but it says "can't save a DBQuery" – vorou Dec 25 '13 at 08:05
  • 1
    I think what you tried failed because the inner db.docs.find query returns an array rather than a document. Save can save a document. See the edit. – Mzzl Dec 25 '13 at 08:15
  • thanks, I've already found that `DBQuery` has `.toArray()` method which does what I want. – vorou Dec 25 '13 at 08:37
  • i have problems with the save array, I used this method:´ `function save_array(arr) { arr.forEach(element => db.result.save(element)); };` – Jesús Sánchez Oct 07 '20 at 23:07
1

As far as I know, there isn't built-in functionality to do this in MongoDB.

Other options would be to use mongoexport/mongoimport or mongodump/mongorestore functionalities.

In both mongoexport and mongodump you can filter the results by adding query options using --query <JSON> or -q <JSON>.

Parvin Gasimzade
  • 25,180
  • 8
  • 56
  • 83
1

If your query is using an aggregation operator then the solution is as sample as using the $out.

I created a sample Collection with the name "tester" which contain the following records.

{ "_id" : ObjectId("4fb36bfd3d1c88bfa15103b1"), "name" : "bob", "value" : 5, "state" : "b"}

{ "_id" : ObjectId("4fb36c033d1c88bfa15103b2"), "name" : "bob", "value" : 3, "state" : "a"} 

{ "_id" : ObjectId("4fb36c063d1c88bfa15103b3"), "name" : "bob", "value" : 7, "state" : "a"}   

{ "_id" : ObjectId("4fb36c0c3d1c88bfa1a03b4"), "name" : "john", "value" : 2, "state" : "a"}

{ "_id" : ObjectId("4fb36c103d1c88bfa5103b5"), "name" : "john", "value" : 4, "state" : "b"} 

{ "_id" : ObjectId("4fb36c143d1c88bfa15103b"), "name" : "john", "value" : 8, "state" : "b"}

{ "_id" : ObjectId("4fb36c163d1c88bfa15103a"), "name" : "john", "value" : 6, "state" : "a"}

Now using the aggregate operator I perform a group by and then save the result into a new collection using this magical operator "$out".

db.tester.aggregate([{$group:{
                                _id:{name:"$name",state:"$state"},
                                min:{$min:"$value"},
                                max:{$max:"$value"},
                               } },
                       {$out:"tester_max_min"}
                     ])

What basically the query is trying to do is, group by name & state and find the min and max values for each individual group, and then save the result into a new collection named "tester_max_min"

db.tester_max_min.find();

The new collection formed will have the following documents in it :

{ "_id" : { "name" : "john", "state" : "b" }, "min" : 4, "max" : 8 }

{ "_id" : { "name" : "john", "state" : "a" }, "min" : 2, "max" : 6 }

{ "_id" : { "name" : "bob", "state" : "a" }, "min" : 3, "max" : 7 }

{ "_id" : { "name" : "bob", "state" : "b" }, "min" : 5, "max" : 5 }

I still need to explore how helpful can $out is but it works like a charm for any aggregator operator.

  • $out will completely replace the original collection if it is pointed to the same collection as the aggregate, so if there is a $match filter everything not matched will be deleted. – user323774 Aug 05 '19 at 19:47