2014-08-30 5 views
0

je travaillais sur mongo et je voudrais faire les choses suivantes:Index et upsert un sous-document mongo

when a set of (lat, lon, uid) comes in: 

1. the collection has lat as unique index, also for each lat the lon index is unique 
2. if (lat, lon) pair exists in this collection, update uid in the sub-document 
3. if (lat) exists in this document , insert (lon, uid) in the lons sub-document 
4. if (lat) document doesn't exist, create lat document and do 2 

[{ 
    "lat" : 1, (doc is unique by lat) 
    "lons" : [ 
     { 
      "lon" : 2, (the subdocument is unique by lon) 
      "uid" : 3 
     }, 
     { 
      "lon" : 3, 
      "uid" : 3 
     } 
    ] 
}, 
{ 
    "lat" : 2, 
    "lons" : [ 
     { 
      "lon" : 2, 
      "uid" : 4 
     } 
    ] 
}] 

J'ai essayé de faire les choses suivantes, mais apparemment il ne fonctionne pas comme ce que je l'imaginais.

db.zones.update({'lat': 90}, {$push: {lons: {'uid' : 0, 'lon': -18}}}, { upsert: true }) 
db.zones.ensureIndex({'lat': -1, 'lons.lon':1}, {unique: true}) 

j'ai vérifié ce poste Can mongo upsert array data? et quelques autres, mais en quelque sorte qu'aucun d'entre eux travaille. Je ne sais pas si c'est mon problème ou mongo. Merci!

Répondre

2

Je vous suggère de reconsidérer votre schéma:

  • Le upsert applique au niveau du document, ce qui ne correspond pas bien avec la façon dont votre schéma est structuré. Si une correspondance n'est pas trouvée dans le tableau lons, vous devez appuyer sur le document existant plutôt que d'en créer un nouveau.

  • documents, y compris des tableaux avec la croissance sans bornes peut conduire à des documents et des déménagements fréquents problèmes de performance (voir: Why shouldn't I embed large arrays in my documents?)

  • Votre schéma ne se prête pas à un indice géospatiale (qui nécessiterait des paires longitude/latitude un tableau ou un document incorporé). Je suppose que ce n'est pas important pour votre cas d'utilisation puisque vous assurez un index unique normal, mais cela pourrait valoir la peine d'être considéré.

Un meilleur schéma (en supposant que vous ne prévoyez pas d'utiliser des requêtes géospatiales) serait:

{ 
    lon: -74.0059, 
    lat: 40.7127, 
    uid: 3 
} 

Avec ce schéma révisé, vos besoins de mise à jour sont plus simples.

  1. la collection a lat index comme unique, également pour chaque lat l'indice de LON est unique

Vous voulez toujours assurer un index unique:

 db.zones.ensureIndex({'lat': 1, 'lon':1}, {unique: true}) 

2. Si la paire (lat, lon) existe dans cette collection, mettez à jour l'ID dans le sous-document

3. Si (lat) existe dans ce document, insérer (lon, uid) dans le sous-document lons

4.si (lat) document n'existe pas, créer un document de latitude et faire 2

Toute cette logique peut désormais être gérée par un upsert:

db.zones.update(

    // query criteria 
    { lat: 40.7127, lon: -74.0060 }, 

    // update 
    { $set: { 
     uid: 3 
    }}, 

    // options 
    { 
     upsert: true 
    } 
) 

Si vous souhaitez conserver le uid lors de l'actualisation d'un document existant, vous pouvez également utiliser l'opérateur $setOnInsert (au lieu de $set):

db.zones.update(

    // query criteria 
    { lat: 40.7127, lon: -74.0060 }, 

    // update 
    { $setOnInsert: { 
     uid: 3 
    }}, 

    // options 
    { 
     upsert: true 
    } 
) 
+0

Je pensais à cela avant. Le problème est que j'aurai environ 10k points en lon et 10k en lat et cela signifie que je vais avoir des documents de 100m créés de cette façon. Est-ce encore un bon design? –

+0

Certainement! Lisez l'article de blog que j'ai référencé sur [grand tableau intégré] (http://askasya.com/post/largeembeddedarrays). Dans les deux cas, vous avez le même nombre d'entrées d'index pour des paires lat/longues uniques, alors considérez les index comme ayant à peu près la même taille. Cependant, si vous avez des tableaux de 10k 'lon 'incorporés dans chaque document' lat', il y a un impact supplémentaire sur les performances lorsque les documents dépassent leur espace sur le disque (chaque fois que le document se déplace, toutes les entrées d'index doivent être mis à jour) et si vous avez besoin de récupérer un seul point dans le document, le serveur doit charger l'ensemble du document dans la RAM. – Stennie

+0

Je vois. pour les documents NxN créés de cette manière est l'heure de la requête O (1) ou O (N^2)? Aussi pourriez-vous me recommander plus de ressources pour la requête, les dépenses d'udpate pour mongo? le truc du gros O? Merci beaucoup !! –