2012-03-13 5 views
0

Nous avons environ 20 millions d'enregistrements dans notre mongodb. Dans ma collection appelée «posts», il y a un champ appelé «id» qui était censé être unique mais maintenant il a tout foiré. Nous voulons juste que ce soit unique et il y a beaucoup de doublons maintenant. Nous voulions juste faire quelque chose comme itérer sur chaque reocrd et lui attribuer un identifiant unique dans une boucle de 1 à 20 millions.Jobsed up ids in mongodb

Quelle serait la façon la plus simple de le faire?

+0

N'y aviez-vous pas un index unique? Qu'en est-il du champ _id? –

+0

@Sergio Tulentsev - _id est intact. Je viens de créer un index sur le champ d'identification, mais c'était après que les identifiants ont été foiré. Je suis assez nouveau à mongo –

+0

Que voulez-vous faire avec les valeurs d'ID en double? –

Répondre

1

Vous pouvez utiliser un script simple comme ceci:

db.posts.dropIndex("*id index name here*"); // Drop Unique index 

counter = 0; 

page = 1; 
slice = 1000; 

total = db.posts.count(); 
conditions = {}; 

while (counter < total) { 

    cursor = db.posts.find(conditions, {_id: true}).sort({_id: 1}).limit(slice); 

    while (cursor.hasNext()) { 
     row = cursor.next(); 
     db.posts.update({_id: row._id}, {$set: {id: ++counter}}); 
    } 

    conditions['_id'] = {$gt: row._id}; 
    print("Processed " + counter + " rows"); 
} 

print('Adding id index'); 
db.posts.ensureIndex({id: 1}, {unique: true, background: false}); 

print("done");     

sauver à assignids.js et courir comme

$ mongo dbname assignids.js 

le tout externe sélectionne 1000 lignes comme un temps, et prévient les délais d'attente du curseur; l'intérieur assigne à chaque rangée un nouvel identifiant incrémental.

+0

Je cours le script maintenant .. il pourrait prendre environ 6 heures, mais j'ai le temps. D'un autre côté, le script ne fonctionnerait pas comme vous l'avez dit. Peut-être que nous devons inclure une commande 'use db' dans votre script. Quoi qu'il en soit, j'ai juste copié et collé votre script sur la ligne de commande après avoir fait une commande 'use db' et son fonctionnement maintenant –

+0

avez-vous oublié l'argument "dbname"?Lorsque vous vous connectez à mongo sur le cli, il vous dira le db auquel il est connecté - par défaut c'est test. 6 heures semble vraiment lent. Comme un ordre de grandeur lente - patience :) – AD7six

+0

oui j'ai oublié le nom de DB. Pardon. –

2

Il n'y a pas beaucoup d'options ici, vraiment.

  1. Choisissez votre langue et le pilote de votre choix.

  2. Récupère N documents.

  3. Attribuez-leur des identifiants uniques (plusieurs options ici: 1) copy _id; 2) assigner un nouvel ObjectID; 3) affecter un entier simple)

  4. Enregistrez ces documents.

  5. Récupère les N prochains documents. Passez à l'étape 3.

Pour récupérer les documents suivants N, vous devez noter le dernier _id du document traité et faire:

db.collection.find({_id: {$gt: last_processed_id}}).sort({_id: 1}).limit(N); 

Est-ce pas SKIP ici. Ce sera trop lent. Et, bien sûr, vous pouvez toujours tronquer la collection, créer un index unique sur id et le remplir à nouveau.

+0

Comment ferais-je pour extraire n documents dans une boucle? Je n'ai pas d'identifiant à récupérer. Je pense que j'utiliserais le _id? Mais encore une fois comment faire des limites? –

+0

@ImranOmarBukhsh: mis à jour la réponse –

+0

ai-je pas besoin de trier? –