MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Nettoyage des fichiers orphelins de GridFS

Tout d'abord, prenons le temps de considérer ce que GridFS en fait est. Et pour commencer, lisons la page de manuel référencée :

Donc, avec cela à l'écart, et cela pourrait bien être votre cas d'utilisation. Mais la leçon à retenir ici est que GridFS n'est pas automatiquement la méthode "go-to" pour stocker les fichiers.

Ce qui s'est passé ici dans votre cas (et d'autres) est dû à la spécification "au niveau du pilote" que c'est (et MongoDB lui-même ne fait non magie ici), vos "fichiers" ont été "divisés" en deux collections. Une collection pour la référence principale au contenu, et l'autre pour les "morceaux" de données.

Votre problème (et d'autres) est que vous avez réussi à laisser derrière vous les "morceaux" maintenant que la référence "principale" a été supprimée. Alors avec un grand nombre, comment se débarrasser des orphelins.

Votre lecture actuelle indique "bouclez et comparez", et puisque MongoDB ne fait pas de jointures , alors il n'y a vraiment pas d'autre réponse. Mais il y a certaines choses qui peuvent aider.

Donc, plutôt que d'exécuter un énorme $nin , essayez de faire quelques choses différentes pour briser cela. Envisagez de travailler dans l'ordre inverse, par exemple :

db.fs.chunks.aggregate([
    { "$group": { "_id": "$files_id" } },
    { "$limit": 5000 }
])

Donc, ce que vous faites là, c'est obtenir le distinct valeurs "files_id" (étant les références à fs.files ), de toutes les entrées, pour 5000 de vos entrées pour commencer. Ensuite, bien sûr, vous revenez à la boucle, en vérifiant fs.files pour un _id correspondant . Si quelque chose n'est pas trouvé, alors supprimez les documents correspondant à "files_id" de vos "morceaux".

Mais ce n'était que 5000, alors gardez le dernier id trouvé dans cet ensemble, car vous allez maintenant exécuter à nouveau la même instruction d'agrégation, mais différemment :

db.fs.chunks.aggregate([
    { "$match": { "files_id": { "$gte": last_id } } },
    { "$group": { "_id": "$files_id" } },
    { "$limit": 5000 }
])

Alors ça marche parce que le ObjectId les valeurs sont monotone ou "toujours en augmentation". Donc tout nouveau les entrées sont toujours plus grandes que le dernier. Ensuite, vous pouvez parcourir à nouveau ces valeurs et effectuer les mêmes suppressions là où elles ne sont pas trouvées.

Est-ce que cela "prendra une éternité". Eh bien oui . Vous pourriez employer db.eval() pour cela, mais lisez La documentation. Mais dans l'ensemble, c'est le prix à payer pour en utiliser deux collections.

Retour au début. Le GridFS la spécification est conçue de cette façon parce qu'il veut spécifiquement contourner la limite de 16 Mo. Mais si ce n'est pas votre limitation, puis demandez pourquoi vous utilisez GridFS en premier lieu.

MongoDB n'a aucun problème stocker des données "binaires" dans n'importe quel élément d'un document BSON donné. Donc, vous n'avez pas besoin utiliser GridFS juste pour stocker des fichiers. Et si vous l'aviez fait, alors tous de vos mises à jour seraient complètement "atomiques", car elles n'agissent que sur une document en un collection à la fois.

Depuis GridFS délibérément divise les documents entre les collections, puis si vous l'utilisez, vous vivez avec la douleur. Alors utilisez-le si vous avez besoin mais si vous ne le faites pas , puis stockez simplement le BinData comme un champ normal, et ces problèmes disparaissent.

Mais au moins, vous avez une meilleure approche à adopter que de tout charger en mémoire.