Salva sottoinsieme della collezione MongoDB in un’altra raccolta

Ho un set come questo

{date: 20120101} {date: 20120103} {date: 20120104} {date: 20120005} {date: 20120105} 

Come posso salvare un sottoinsieme di questi documenti con la data “20120105” in un’altra raccolta?

es. db.subset.save(db.full_set.find({date: "20120105"}));

Ecco la versione della shell:

 db.full_set.find({date:"20120105"}).forEach(function(doc){ db.subset.insert(doc); }); 

Nota: A partire da MongoDB 2.6, il framework di aggregazione rende ansible farlo più velocemente; vedi la risposta di Melan per i dettagli.

Come soluzione più recente, consiglierei di utilizzare il framework Aggregation per il problema:

db.full_set.aggregate([ { $match: { date: "20120105" } }, { $out: "subset" } ]);

Funziona circa 100 volte più velocemente di almeno per me nel mio caso. Questo perché l’intera pipeline di aggregazione viene eseguita nel processo mongod, mentre una soluzione basata su find() e insert() deve inviare tutti i documenti dal server al client e quindi tornare indietro. Questo comporta una penalizzazione delle prestazioni, anche se il server e il client si trovano sulla stessa macchina.

In realtà, c’è un equivalente dell’inserto di SQL insert into ... select from in MongoDB. Innanzitutto, converti più documenti in una matrice di documenti; quindi si inserisce la matrice nella raccolta di destinazione

 db.subset.insert(db.full_set.find({date:"20120105"}).toArray()) 

La soluzione più generale è questa:

Sfruttare l’aggregazione (risposta data da @melan):

 db.full_set.aggregate({$match:{your query here...}},{$out:"sample"}) db.sample.copyTo("subset") 

Funziona anche quando ci sono documenti in “sottoinsieme” prima dell’operazione e si desidera conservare quei “vecchi” documenti e inserire solo un nuovo sottoinsieme.

Bisogna fare attenzione, perché il comando copyTo() sostituisce i documenti con lo stesso _id .

Non esiste un equivalente diretto dell’inserto di SQL insert into ... select from ...

Devi prenderti cura di te stesso. Recupera documenti di interesse e salvali in un’altra raccolta.

Puoi farlo nella shell, ma userei un piccolo script esterno in Ruby. Qualcosa come questo:

 require 'mongo' db = Mongo::Connection.new.db('mydb') source = db.collection('source_collection') target = db.collection('target_collection') source.find(date: "20120105").each do |doc| target.insert doc end 

$ out Prende i documenti restituiti dalla pipeline di aggregazione e li scrive in una raccolta specificata.

  • L’operazione $ out crea una nuova raccolta nel database corrente se non esiste già.
  • La raccolta non è visibile fino al completamento dell’aggregazione.
  • Se l’aggregazione fallisce, MongoDB non crea la raccolta.

Sintassi:

 { $out: "" } 

Esempio Un libro di raccolta contiene i seguenti documenti:

 { "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 } { "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 } { "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 } { "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 } { "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 } 

La seguente operazione di aggregazione fa ruotare i dati nella raccolta di libri per disporre di titoli raggruppati per autori e quindi li scrive nella raccolta degli autori.

 db.books.aggregate( [ { $group : { _id : "$author", books: { $push: "$title" } } }, { $out : "authors" } ] ) 

Dopo l’operazione, la raccolta degli autori contiene i seguenti documenti:

 { "_id" : "Homer", "books" : [ "The Odyssey", "Iliad" ] } { "_id" : "Dante", "books" : [ "The Banquet", "Divine Comedy", "Eclogues" ] } 

Nella domanda, usa la seguente query e otterrai una nuova raccolta denominata ‘col_20120105’ nel tuo database

  db.products.aggregate([ { $match : { date : "20120105" } }, { $out : "col_20120105" } ]);