2009-08-29 19 views
15

ブログを構築していた場合は、ブログタイトルを一意の識別子として使用してURLを解析することができます。しかし、もし私が数字を使いたければどうでしょうか?あなたはTwitterがどのようにwww.twitter.com/username/statuses/9834542を持っているか知っていますか?誰もがこの仕事をする良い方法を考え出しましたか? "_id"を使っているのは時間がかかりすぎているからです。mongodbの一意のID

+0

URLのmd5(または任意の)ハッシュを実行して、_idの場所に格納することができます。 –

答えて

22

一意性を保証できる限り、デフォルトの "_id" MongoDBサプライを使用することに制約はありません。

したがって、この番号をどのように生成するかはあなた次第です。この番号をMongoDBの中に保存したいのであれば、それを別のコレクションに保存し、必要な新しいURLごとにそれを増やすことができます。

the $inc verbを使用してフィールドをインクリメントするか、MongoDBがatomically updateをどのように使用できるかを調べるか、値を増分したい場合があります。

+0

アランが言ったように、あなたは自分のIDを提供することができます。だから問題は、それを独自に生成する方法です。このシーケンスサーバーはシーケンスごとに単一のモンゴレコードを使用することができます –

7

MongoDBの独自のフィールドに一意制約を追加する場合は、インデックスを使用します。次に、番号を生成して一意性をテストする任意のハッシングアルゴリズムを使用できます。 MongoDBのドキュメントの例では、他の文書と同じ姓と名で文書を挿入を防止することができます

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

です。

さらに詳しい情報はdocumentationでご覧になれます。

4

私はデータを収集 '配列' を作成することで、この問題を解決した:

  • currurt値

私はMorhpiaを使用して、それのためのDAOを持っています。しかし、あなたはMorhpiaなしでもそれを行うことができます。 アイデアは$ atomicを使用することです(おそらく、1インスタンスのみの更新で省略できます)。$inc修飾子演算子です。 SequenceDAO上

シーケンス

@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 
} 

方法:

@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の構成に応じて(1つのノードのみ、またはマスタ/スレーブまたはレプリカセット)あなたは正しいWriteConcernを使用する必要があります。 1つのインスタンスで1つの環境でREPLICATION_SAFEを使用すると、無限ループが発生します。

+0

これはどの言語ですか:)ヒットマイ眼! – asyncwait

15

findandmodifyコマンドを使用して実行できます。

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

は、このコマンドは、アトミックに更新返します。

、あなたがこのようなコードを使用することができますのは、私たちがsequencesという名前の特別なコレクションを持って考えると、私たちは(postidという名前)郵便番号の列を持ちたいです(new)のドキュメントをステータスとともに表示します。 valueフィールドには、コマンドが正常に完了した場合に返されるドキュメントが格納されます。

+0

シャード環境ではどのようにしてこの作品を制作しますか? – BlitzKrieg

+0

@BlitzKrieg、ドキュメントごと: "* findandmodify *は、変更対象のコレクションが非共有である限り、mongosを通じて呼び出されたときと同じように動作します。コレクションがシャードされている場合、クエリにはシャードキーが含まれている必要があります。ですから 'sequences'コレクションを破棄しないでください。 –

+0

これは@Hubert ...ありがとう! – BlitzKrieg

1

技術的には、ID番号が大きすぎて短縮することはできません。しかし、戦術を埋めることができます。これは、16進数から英数字への変換で、文字数を減らし、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!!! 

もちろん、この技術は同じid、mongoを使用します。

関連する問題