2009-08-29 36 views
15

Gdybym budował bloga, mógłbym użyć tytułu bloga jako unikalnego identyfikatora i przetworzyć go przez URL. Ale co, gdybym chciał użyć liczb. Wiesz, jak twitter ma www.twitter.com/username/statuses/9834542? Czy ktoś wymyślił dobry sposób na wykonanie tej pracy? używanie "_id" nie wchodzi w grę, ponieważ jest zbyt długo.Unikalne identyfikatory z mongodb

+0

Możesz zrobić md5 (lub dowolny) skrót adresu URL i zapisać go w miejscu _id. –

Odpowiedz

22

Dopóki możesz zagwarantować wyjątkowość, nie jesteś zmuszony do używania domyślnych "_id" materiałów MongoDB.

W związku z tym od Ciebie zależy, w jaki sposób wygenerujesz ten numer. Jeśli chcesz zapisać ten numer w MongoDB, możesz przechowywać go w osobnej kolekcji i zwiększać go dla każdego nowego wymaganego adresu URL.

Zwiększenie wartości pola można uzyskać za pomocą metody the $inc verb. Można również sprawdzić, w jaki sposób MongoDB może atomically update lub zwiększyć wartość.

+0

Jak powiedział Alan, możesz podać własny identyfikator. Pytanie więc, w jaki sposób można je wygenerować w sposób unikalny. Najłatwiej jest, jeśli miałeś jakiś serwer sekwencji (tj. Coś, co rozdaje liczbę, a następnie inkrementuje, trzymając zamek tak, że to dzieje się atomowo.Ten serwer sekwencji mógłby użyć pojedynczego rekordu mongo na sekwencję –

7

Jeśli chcesz dodać ograniczenie unikalności do własnego pola w MongoDB, użyj indeksu. Następnie możesz użyć dowolnego algorytmu mieszania, który chcesz wygenerować i przetestować pod kątem unikalności. Przykład w dokumentacji MongoDB jest

db.things.ensureIndex({firstname: 1, lastname: 1}, {unique: true}); 

który uniemożliwi włożenie dokumentów z tego samego Imię i nazwisko jako innego dokumentu.

Więcej informacji dostępnych jest w documentation.

4

Mam rozwiązać ten problem, tworząc kolekcję 'sekwencji' z danymi:

  • nazwa
  • wartość currurt

Używam Morhpia, więc mają DAO dla niego. Ale możesz to zrobić także bez Morhpii. Pomysł polega na użyciu operatora $ atomic (prawdopodobnie można go pominąć tylko z powodu aktualizacji 1 instancji) i $inc.

Sequence

@Entity(value = "sys_sequence", noClassnameStored = true) 
public class SequenceM { 

    /** 
    * Names of entity 
    */ 
    public static enum Entity { 
     USER, 
     CAPABILITY_HISTORY; 

     public String getEntityName() { 
      return this.name().toLowerCase(); 
     } 
    } 

    @Id 
    private ObjectId uid; 

    @Property 
    @Indexed(unique = true) 
    private String name; 

    @Property 
    private Long value; 

//..getters/setters/etc 
} 

Sposób na SequenceDAO:

@NotNull 
public Long nextValue(final @NotNull SequenceM.Entity entity) { 
    final DB db = this.ds.getDB(); 
    final WriteConcern writeConcern = getWriteConcern(); 

    //optimization for JVM instance 
    synchronized(entity) { 
     do { 
      SequenceM sequence = findOne("name", entity.getEntityName()); 

      final DBObject q = BasicDBObjectBuilder.start().add("name", entity.getEntityName()).add("value", sequence.getValue()).add("$atomic", 1).get(); 
      final DBObject o = BasicDBObjectBuilder.start().add("$inc", BasicDBObjectBuilder.start().add("value", 1).get()).get(); 

      WriteResult writeResult = db.getCollection("sys_sequence").update(q, o, false, true, writeConcern); 

      if(writeResult.getN() == 1) { 
       return sequence.getValue() + 1; 
      } 
     } while(true); 
    } 
} 

/** 
* Determining writing concern basing on configuration 
*/ 
private WriteConcern getWriteConcern() { 
    return isOneNodeOnly ? WriteConcern.SAFE : REPLICATION_SAFE; 
} 

zależności od konfiguracji MongoDB (tylko jeden węzeł lub master/slave lub zestaw replik) trzeba użyć prawidłowego WriteConcern. Używanie REPLICATION_SAFE w jednym środowisku z jedną instancją powoduje tylko nieskończoną pętlę.

+0

Jaki to jest język? :) Odgrywa moje oko! – asyncwait

15

Można to zrobić za pomocą polecenia findandmodify.

Rozważmy mamy specjalną kolekcję o nazwie sequences i chcemy mieć sekwencję liczb post (nazwanych postid), można użyć kodu podobnego do tego:

 
> db.runCommand({ "findandmodify" : "sequences", 
        "query" : { "name" : "postid"}, 
        "update" : { $inc : { "id" : 1 }}, 
        "new" : true }); 

To polecenie zwróci atomowo zaktualizowany (new) dokument wraz ze statusem. Pole value zawiera zwracany dokument, jeśli polecenie zakończyło się pomyślnie.

+0

Jak sprawić, by ta praca działała w zaciemnionym środowisku? – BlitzKrieg

+0

@BlitzKrieg, zgodnie z dokumentacją: "* findandmodify * będzie zachowywać się tak samo, gdy zostanie wywołane przez mongos, o ile kolekcja, którą modyfikuje, jest niezałatwiona.Jeśli kolekcja jest zignorowana, zapytanie musi zawierać klucz shard." Więc, po prostu nie ukrywaj kolekcji 'sequence'? –

+0

Mam to @Hubert ... Dzięki! – BlitzKrieg

1

Technicznie numer identyfikacyjny jest zbyt duży, aby go skrócić.Można jednak zastosować taktykę. To przechodzi z Hex do alfanumerycznego, zmniejszając w ten sposób liczbę znaków do tulizara i wygląda piękniej w Url. Naprawdę dobrze służyłem ... tutaj jest

function encode(hex) { 
    return new Buffer(hex, 'hex').toString('base64').replace('+', '-').replace('/', '_'); 
}; 

function decode(NoHex) { 
    return new Buffer(NoHex.replace('-','+').replace('_','/'), 'base64').toString('hex'); 
}; 

IdString= MyDoc._id.toString(); 
Idencode = encode(IdString) // 16 Caracters a-Z and 0-9 
console.log(IdEncode); //You see That 'aqswedasdfdsadsf' 
IdDecode = decode(IdEncode); 
IdDecode === IdString // Is true!!! 

Oczywiście ta technika używa tego samego id, mongo.