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
Odpowiedz
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ść.
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ę –
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.
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ę.
Jaki to jest język? :) Odgrywa moje oko! – asyncwait
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.
Jak sprawić, by ta praca działała w zaciemnionym środowisku? – BlitzKrieg
@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'? –
Mam to @Hubert ... Dzięki! – BlitzKrieg
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.
Możesz zrobić md5 (lub dowolny) skrót adresu URL i zapisać go w miejscu _id. –