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.
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" } ]);