Comment puis-je (dans MongoDB) combiner les données de plusieurs collections en une seule collection?
Puis-je utiliser map-Reduce et si oui, comment?
J'apprécierais grandement un exemple car je suis novice.
mongodb
mongodb-query
aggregation-framework
user697697
la source
la source
db.collection1.find().forEach(function(doc){db.collection2.save(doc)});
suffit. Veuillez spécifier votre pilote utilisé (java, php, ...) si vous n'utilisez pas le shell mongo.Réponses:
Bien que vous ne puissiez pas le faire en temps réel, vous pouvez exécuter plusieurs fois map-réduire pour fusionner les données en utilisant l'option "réduire" dans MongoDB 1.8+ map / Reduce (voir http://www.mongodb.org/ display / DOCS / MapReduce # MapReduce-Outputoptions ). Vous devez avoir une clé dans les deux collections que vous pouvez utiliser comme _id.
Par exemple, supposons que vous ayez une
users
collection et unecomments
collection et que vous souhaitiez avoir une nouvelle collection contenant des informations démographiques sur l'utilisateur pour chaque commentaire.Supposons que la
users
collection comporte les champs suivants:Et puis la
comments
collection a les champs suivants:Vous feriez cette carte / réduisez:
À ce stade, vous aurez une nouvelle collection appelée
users_comments
qui contient les données fusionnées et vous pouvez maintenant l'utiliser. Ces collections réduites ont toutes_id
la clé que vous émettiez dans vos fonctions de carte, puis toutes les valeurs sont un sous-objet à l'intérieur duvalue
clé - les valeurs ne sont pas au niveau supérieur de ces documents réduits.Ceci est un exemple quelque peu simple. Vous pouvez répéter cela avec plus de collections autant que vous le souhaitez pour continuer à constituer la collection réduite. Vous pouvez également faire des résumés et des agrégations de données au cours du processus. Vous définiriez probablement plus d'une fonction de réduction, car la logique d'agrégation et de conservation des champs existants devient plus complexe.
Vous remarquerez également qu'il existe désormais un document pour chaque utilisateur avec tous les commentaires de cet utilisateur dans un tableau. Si nous fusionnions des données qui ont une relation un-à-un plutôt qu'un-à-plusieurs, ce serait plat et vous pourriez simplement utiliser une fonction de réduction comme celle-ci:
Si vous souhaitez aplatir la
users_comments
collection afin qu'elle soit un document par commentaire, exécutez également ceci:Cette technique ne doit certainement pas être effectuée à la volée. Il convient à un travail cron ou quelque chose comme ça qui met à jour périodiquement les données fusionnées. Vous voudrez probablement exécuter
ensureIndex
la nouvelle collection pour vous assurer que les requêtes que vous effectuez contre elle s'exécutent rapidement (gardez à l'esprit que vos données sont toujours dans unevalue
clé, donc si vous deviez indexercomments_with_demographics
l'created
heure du commentaire , ce seraitdb.comments_with_demographics.ensureIndex({"value.created": 1});
la source
users_comments
collection après le premier bloc de code gist.github.com/nolanamy/83d7fb6a9bf92482a1c4311ad9c78835MongoDB 3.2 permet désormais de combiner les données de plusieurs collections en une seule à travers l' étape d'agrégation $ lookup . À titre d'exemple pratique, disons que vous disposez de données sur les livres divisées en deux collections différentes.
Première collecte, appelée
books
, contenant les données suivantes:Et la deuxième collection, appelée
books_selling_data
, contenant les données suivantes:Pour fusionner les deux collections, il suffit d'utiliser la recherche $ de la manière suivante:
Après cette agrégation, la
books
collection ressemblera à ceci:Il est important de noter quelques éléments:
books_selling_data
, la collection "from" ne peut pas être fragmentée.Donc, en conclusion, si vous voulez consolider les deux collections, ayant, dans ce cas, un champ plat copies_sold avec le total des copies vendues, vous devrez travailler un peu plus, probablement en utilisant une collection intermédiaire qui, alors, être $ à la collection finale.
la source
$lookup
tous les deux "localField" et "foreignField" ne devrait-il pas être égal à "isbn"? pas "_id" et "isbn"?S'il n'y a pas d'insertion en masse dans mongodb, nous bouclons tous les objets dans le
small_collection
et les insérons un par un dans lebig_collection
:la source
Exemple très basique avec $ lookup.
Ici est utilisé
Au lieu de
Parce que {$ unwind: "$ userRoleData"} cela retournera un résultat vide ou 0 si aucun enregistrement correspondant trouvé avec $ lookup.
la source
Il est possible d'effectuer des unions dans MongoDB à la manière d'un 'SQL UNION' en utilisant des agrégations avec des recherches, dans une seule requête. Voici un exemple que j'ai testé qui fonctionne avec MongoDB 4.0:
Voici l'explication de son fonctionnement:
Instancier une
aggregate
de toute collection de votre base de données qui a au moins un document en elle. Si vous ne pouvez garantir qu'une collection de votre base de données ne sera pas vide, vous pouvez contourner ce problème en créant dans votre base de données une sorte de collection `` factice '' contenant un seul document vide qui sera là spécifiquement pour effectuer des requêtes d'union.Faites de la première étape de votre pipeline
{ $limit: 1 }
. Cela supprimera tous les documents de la collection, sauf le premier.Supprimez tous les champs du document restant à l'aide d'une
$project
étape:Votre agrégat contient désormais un seul document vide. Il est temps d'ajouter des recherches pour chaque collection que vous souhaitez réunir. Vous pouvez utiliser le
pipeline
champ pour effectuer un filtrage spécifique, ou laisserlocalField
etforeignField
comme null pour correspondre à l'ensemble de la collection.Vous avez maintenant un agrégat contenant un seul document qui contient 3 tableaux comme celui-ci:
Vous pouvez ensuite les fusionner ensemble dans un seul tableau à l'aide d'une
$project
étape avec l'$concatArrays
opérateur d'agrégation:Vous avez maintenant un agrégat contenant un seul document, dans lequel se trouve un tableau qui contient votre union de collections. Ce qui reste à faire est d'ajouter une
$unwind
et une$replaceRoot
étape pour diviser votre tableau en documents séparés:Voilà. Vous disposez maintenant d'un jeu de résultats contenant les collections que vous souhaitez réunir. Vous pouvez ensuite ajouter plus d'étapes pour le filtrer davantage, le trier, appliquer skip () et limit (). À peu près tout ce que vous voulez.
la source
utiliser plusieurs recherches $ pour plusieurs collections en agrégation
requete:
résultat:
la source
Mongorestore a cette fonctionnalité d'ajouter au-dessus de tout ce qui est déjà dans la base de données, donc ce comportement pourrait être utilisé pour combiner deux collections:
Je ne l'ai pas encore essayé, mais il pourrait fonctionner plus rapidement que l'approche carte / réduire.
la source
En commençant
Mongo 4.4
, nous pouvons réaliser cette jointure au sein d'un pipeline d'agrégation en couplant la nouvelle$unionWith
étape d'agrégation avec$group
le nouvel$accumulator
opérateur de:$unionWith
combine les enregistrements de la collection donnée dans des documents déjà dans le pipeline d'agrégation. Après les 2 étapes de l'union, nous avons donc tous les utilisateurs, livres et enregistrements de films dans le pipeline.Nous
$group
enregistrons ensuite par$user
et accumulons des éléments à l'aide de l'$accumulator
opérateur permettant des accumulations personnalisées de documents au fur et à mesure qu'ils sont regroupés:accumulateArgs
.init
définit l'état qui sera accumulé lorsque nous regrouperons les éléments.accumulate
fonction permet d'effectuer une action personnalisée avec un enregistrement en cours de regroupement afin de construire l'état accumulé. Par exemple, si l'élément en cours de regroupement a lebook
champ défini, nous mettons à jour labooks
partie de l'état.merge
est utilisé pour fusionner deux états internes. Il n'est utilisé que pour les agrégations s'exécutant sur des clusters fragmentés ou lorsque l'opération dépasse les limites de la mémoire.la source
Oui, vous pouvez: Prenez cette fonction utilitaire que j'ai écrite aujourd'hui:
Vous pouvez passer à cette fonction n'importe quel nombre de collections, la première va être la cible. Toutes les autres collections sont des sources à transférer vers la cible.
la source
Extrait de code. Courtoisie - Plusieurs messages sur le débordement de la pile, y compris celui-ci.
la source
Vous devez le faire dans votre couche d'application. Si vous utilisez un ORM, il pourrait utiliser des annotations (ou quelque chose de similaire) pour extraire des références qui existent dans d'autres collections. Je n'ai travaillé qu'avec Morphia , et l'
@Reference
annotation récupère l'entité référencée lorsqu'elle est interrogée, donc je peux éviter de le faire moi-même dans le code.la source