Уникальные идентификаторы с mongodb
Если бы я создавал блог, я мог бы использовать заголовок блога в качестве уникального идентификатора и анализировать его по URL. Однако, что, если я хотел бы использовать числа. Вы знаете, как твиттер имеет www.twitter.com/username/statuses/9834542? Кто-нибудь нашел хороший способ сделать эту работу? использование "_id" исключено, поскольку это слишком долго.
5 ответов
Пока вы можете гарантировать уникальность, вы не обязаны использовать поставляемые по умолчанию "_id" MongoDB.
Поэтому вам решать, как вы сгенерируете это число. Если вы хотите сохранить этот номер внутри MongoDB, вы можете сохранить его в отдельной коллекции и увеличивать его для каждого нового требуемого URL-адреса.
Увеличение поля достигается с помощью $inc
или вы можете захотеть взглянуть на то, как MongoDB может атомарно обновлять или увеличивать значение.
Это можно сделать с помощью команды findandmodify.
Давайте рассмотрим, у нас есть специальная коллекция с именем sequences
и мы хотим иметь последовательность для номеров сообщений (названный postid
), вы можете использовать код, подобный следующему:
> db.runCommand ({"findandmodify": "sequence", "query": { "name": "postid"}, "update": { $inc: { "id": 1 }}, "new": true });
Эта команда вернет атомарно обновленный (new
) документ вместе со статусом. value
поле содержит возвращенный документ, если команда выполнена успешно.
Если вы хотите добавить ограничение уникальности в собственное поле в MongoDB, используйте индекс. Затем вы можете использовать любой алгоритм хеширования, который хотите сгенерировать, и проверить его на уникальность. Пример в документации MongoDB:
db.things.ensureIndex({firstname: 1, lastname: 1}, {unique: true});
что помешает вам вставить документы с тем же именем и фамилией, что и другой документ.
Более подробная информация доступна в документации.
Я решил эту проблему, создав коллекцию 'sequence' с данными:
- название
- текущая стоимость
Я использую Morhpia, поэтому для этого есть DAO. Но ты можешь сделать это и без Морпии. Идея состоит в том, чтобы использовать $atomic (возможно, его можно опустить из-за обновления только 1 экземпляра) и оператора модификатора $inc.
Последовательность
@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
}
Метод на 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;
}
В зависимости от конфигурации MongoDB (только один узел или главный / подчиненный или набор реплик) вы должны использовать правильный WriteConcern. Использование REPLICATION_SAFE в одной среде с одним экземпляром вызывает только бесконечный цикл.
Технически, идентификационный номер слишком велик, чтобы его сократить. Однако тактику можно заполнить. То есть происходит переход от шестнадцатеричного алфавита к буквенно-цифровому, что сокращает количество символов до тулизара и выглядит более красиво в URL. Я действительно служил очень хорошо... вот
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!!!
Конечно, эта техника использует тот же идентификатор, монго.