İki farklı koleksiyonda yinelenen Mongo ObjectId oluşturma olasılığı var mı?


187

İki farklı koleksiyonda bir belge için aynı Mongo ObjectId oluşturulabilir mi? Kesinlikle çok olası olmadığını anlıyorum, ama mümkün mü?

Çok spesifik olmadan, sormamın nedeni, üzerinde çalıştığım bir uygulama ile sitemizin tam teşekküllü kullanıcılarına dönüştürmeyi umduğumuz seçilmiş yetkililerin kamu profillerini göstermemiz. Sitemize üye olmayan kullanıcılar ve seçilmiş yetkililer için ayrı koleksiyonlarımız var. Seçilen yetkililer hakkında seçilen resmi ObjectId kullanan kişiyle eşleşen çeşitli veriler içeren başka belgeler de vardır.

Hesabı oluşturduktan sonra, seçilen yetkiliyle ilişkilendirilen verileri hala vurgulamaktayız, ancak şimdi de profillerini uygulamamızla etkileşimlerle eşleştirmek için ObjectId ile ilgili kullanıcılara sahip kullanıcı koleksiyonunun bir parçasıdır.

Uygulamamızı birkaç ay önce MySql'den Mongo'ya dönüştürmeye başladık ve geçiş halindeyken bu veri türlerinin her ikisi için eski MySql kimliğini saklıyoruz ve şimdi seçilen resmi Mongo ObjectId'yi kullanıcılarda depolamaya başlıyoruz Seçilen resmi verilere eşlemek için bir belge.

Sadece işleri basitleştirmek için yeni seçilen ObjectId olarak yeni kullanıcı ObjectId belirterek duruyordu ama mevcut herhangi bir kullanıcı ObjectId ile bir çarpışma olması mümkün olmadığından emin olmak istedim.

Fikriniz için teşekkürler.

Edit: Bu soruyu gönderdikten kısa bir süre sonra, önerilen çözümün çok iyi bir fikir olmadığını fark ettim. Mevcut şemamızı yerinde tutmak ve kullanıcı belgesindeki seçilmiş resmi '_id' ile bağlantı kurmak daha iyi olur.



1
Bu sayfayı daha önce okumuştum. İronik bir şekilde daha önceki bir cevapta aynı sayfaya bağlandım. Ve "benzersiz olma olasılığı yüksek" feragatnamesini gördüm, ancak koleksiyonun içine sokulup eklenmediğinden emin değildim. Emin değilim ne tam olarak ObjectId 2 bayt İşlem KIMLIĞI kısmı gerçekten temsil eder. Koleksiyon ile ilgili bir şey varsa, aynı anda farklı koleksiyonlarda aynı makinede oluşturulan iki farklı belge arasında benzersizlik olacaktır.
Anthony Jack

1
2 bayt işlem kimliği, ObjectID oluşturan işlemin pididir. Örnek olarak, pymongo'nun ObjectID'leri oluşturmak için kullandığı kod şöyledir: github.com/mongodb/mongo-python-driver/blob/master/bson/…
mstearn

Karşılaştığım bir şey, toplu ekleme. 10k'lık belgelerden oluşan gruplar oluşturuyordum ve her seferinde çarpışıyordum çünkü sayaç kısmı her seferinde devriliyordu.
fawce

Bir süre geçtiğini biliyorum, ama 10 bin belge tezgahın üzerine gelmeyecekti. Karşı kısım üç bayt değil, üç bayttır. Bu 16 milyondan fazla.
Asya Kamsky

Yanıtlar:


318

Kısa cevap

Yalnızca ilk sorunuza doğrudan bir yanıt eklemek için: EVET, BSON Nesne Kimliği oluşturma kullanıyorsanız, çoğu sürücü için kimlikler koleksiyonlar arasında neredeyse kesinlikle benzersiz olacaktır. "Neredeyse kesinlikle" ne anlama geldiğini görmek için aşağıya bakın.

Uzun cevap

Mongo DB sürücüleri tarafından oluşturulan BSON Nesne Kimlikleri, koleksiyonlar arasında benzersiz olacaktır. Bunun nedeni, çoğu sürücü için statik bir artan sayaç aracılığıyla üretilen kimliğin son 3 baytıdır . Bu sayaç koleksiyondan bağımsızdır; küreseldir. Örneğin, Java sürücüsü rastgele başlatılan statik bir AtomicInteger kullanır.

Peki, neden Moğol belgelerinde, kimliklerin benzersiz olacağını söylemek yerine kimliklerin benzersiz olma olasılığının yüksek olduğunu söylüyorlar? Benzersiz bir kimlik alamayacağınız üç olasılık ortaya çıkabilir (lütfen daha fazlası varsa bana bildirin):

Bu tartışmadan önce, BSON Nesne Kimliğinin aşağıdakilerden oluştuğunu hatırlayın:

[Dönemden bu yana 4 bayt saniye, 3 bayt makine karması, 2 bayt işlem kimliği, 3 bayt sayacı]

İşte üç olasılık, bu yüzden bir dupe edinmenin ne kadar olası olduğunu kendiniz değerlendiriyorsunuz:

1) Sayaç taşması: sayaçta 3 bayt var. Tek bir saniyede, aynı makinede, aynı işlemde 16.777.216 (2 ^ 24) 'den fazla belge eklerseniz, artan sayaç baytlarını aşabilir ve aynı zamanı paylaşan iki Nesne Kimliği ile sonuçlanabilir, makine , süreç ve sayaç değerleri.

2) Sayaç artmaz: Bazı Mongo sürücüleri sayaç baytları için sayıları artırmak yerine rastgele sayılar kullanır. Bu gibi durumlarda, benzersiz olmayan bir kimlik oluşturma olasılığı 1 / 16,777,216 olabilir, ancak yalnızca bu iki kimlik aynı saniyede (yani, kimliğin zaman bölümünden sonraki saniyeye güncellenmeden önce) oluşturulursa makine, aynı süreçte.

3) Makine ve proses karması aynı değerlere getirilir. Makine kimliği ve işlem kimliği değerleri, bazı olası olmayan senaryolarda, iki farklı makine için aynı değerlerle eşlenebilir. Bu gerçekleşirse ve aynı anda iki farklı makinedeki iki sayaç aynı saniye boyunca aynı değeri üretirse, yinelenen bir kimlikle sonuçlanırsınız.

Bunlar dikkat edilmesi gereken üç senaryodur. Senaryo 1 ve 3 pek olası görünmüyor ve doğru sürücüyü kullanıyorsanız senaryo 2 tamamen önlenebilir. Emin olmak için sürücünün kaynağını kontrol etmeniz gerekir.


3 bayt sayacı, makine başına işlem başına saniye başına eklenen 2 ^ 24 = 16777216 belge sayısını kabul etme yeteneğini temsil etmiyor mu?
Forrest Ye

Kesinlikle haklısın, yanlışlıkla bit sayısını yarıya indirdim - cevap değiştirildi.
Raj Advani

Buna yeni adım attığım için, bazı sürücülerin (örn. C) artışlar kullansa da, atomik olarak artmadığını, bu nedenle zaman zaman, yarış durumu nedeniyle aynı
yağı ürettiğini ekleyeyim

39
136 yıl içinde ObjectId, makinenin karması, işlem kimliği ve sayacının hepsi aynı olduğu sürece daha önce yaptığınızla aynı şeyi üretmek için başka bir vuruşunuz olduğu
gerçeğini atladınız

25
@jamylak Acil olduğunda bu sorunu halledeceğiz (70'lerde YYMMDD tarih formatlarını standardize eden insanlar söyledi)
Philipp

14

ObjectIds, istemci tarafında UUID'ye benzer bir şekilde üretilir, ancak bir veritabanında saklamak için bazı güzel özellikler, sırayla kabaca artan sipariş ve oluşturma sürelerini ücretsiz olarak kodlama gibi. Kullanım durumunuz için en önemli şey, farklı makinelerde üretilse bile yüksek olasılıkta benzersizliği garanti etmek için tasarlanmış olmalarıdır.

Genel olarak _id alanına atıfta bulunuyorsanız, koleksiyonlar arasında benzersizliğe gerek duymuyoruz, bu nedenle eski _id'i yeniden kullanmak güvenlidir. Somut bir örnek olarak, iki koleksiyonunuz varsa colorsve fruitsher ikisinin de aynı anda bir nesnesi olabilir {_id: 'orange'}.

ObjectIds'ın nasıl oluşturulduğu hakkında daha fazla bilgi edinmek istiyorsanız, teknik özellik şudur: http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-BSONObjectIDSpecification


11

Herkes yinelenen Mongo ObjectID'lerle ilgili sorun yaşıyorsa, Mongo'nun kendisinde meydana gelen duplerin olma olasılığına rağmen, Mongo'da PHP ile yinelenen _id'ler oluşturmanın mümkün olduğunu bilmelisiniz.

Bunun benim için düzenli bir şekilde gerçekleştiği kullanım örneği, bir veri kümesinde döngü yaptığım ve verileri bir koleksiyona enjekte etmeye çalıştığım zamandır.

Enjeksiyon verilerini tutan dizi, _id değerini belirtmeseniz bile her yinelemede açıkça sıfırlanmalıdır. Nedense, INSERT işlemi diziye genel bir değişkenmiş gibi diziye Mongo _id değerini ekler (dizi genel kapsamı olmasa bile). Eklemeyi normalde dizinin değerlerinin arama işlevine geri dönmemesini beklediğiniz ayrı bir işlev çağrısında çağırsanız bile bu durum sizi etkileyebilir.

Bunun üç çözümü var:

  1. unset()Diziden _id alanını yapabilirsiniz
  2. array()Veri kümenizde her döngü yaptığınızda dizinin tamamını yeniden başlatabilirsiniz
  3. _İd değerini açıkça kendiniz tanımlayabilirsiniz (değeri kendiniz dup oluşturmayacak şekilde tanımlamaya özen gösterin).

Benim tahminim, bu PHP arayüzünde bir hata ve Mongo ile ilgili bir sorun değil, ama bu sorunla karşılaşırsanız, _id ayarını kaldırın ve iyi olmalısınız.


buraya bakın: php.net/manual/tr/mongocollection.insert.php : "Not: Parametrenin _id anahtarı veya özelliği yoksa, yeni bir MongoId örneği oluşturulur ve atanır. Bu özel davranış, . parametre referans olarak geçirilir olduğu ", bir özellik değil, bir böcek, şekilde olması gerekiyordu
Oliver Konig

1
Burada anlattığınız senaryoyu anlamıyorum; belki de hata gösteren bir kod gösterebilir?
Mark Amery

-7

Koleksiyonlar arasında ObjectId benzersizliği hakkında hiçbir garanti yoktur. Muhtemelen pek olası olmasa bile, koleksiyonlar arasında benzersizliği temel alan çok zayıf bir uygulama tasarımı olurdu.

Bunu kolayca mongo kabuğunda test edebilirsiniz:

MongoDB shell version: 1.6.5
connecting to: test
> db.foo.insert({_id: 'abc'})
> db.bar.insert({_id: 'abc'})
> db.foo.find({_id: 'abc'})
{ "_id" : "abc" }
> db.bar.find({_id: 'abc'})
{ "_id" : "abc" }
> db.foo.insert({_id: 'abc', data:'xyz'})
E11000 duplicate key error index: test.foo.$_id_  dup key: { : "abc" }

Bu nedenle, _id'in koleksiyonlar arasında benzersiz olmasına kesinlikle güvenmeyin ve ObjectId oluşturma işlevini denetlemediğiniz için ona güvenmeyin.

Daha uuid gibi bir şey yaratmak mümkündür ve bunu manuel olarak yaparsanız, benzersizliğin daha iyi bir garantisine sahip olabilirsiniz.

Aynı koleksiyona farklı "tip" nesneler koyabileceğinizi unutmayın, neden iki "tablonuzu" aynı koleksiyona koymuyorsunuz? Aynı _id alanını paylaşacaklar ve böylece benzersiz bir garanti verileceklerdi. "Potansiyel" den "kayıtlı" durumuna geçmek bir alanın basitçe çevrilmesi anlamına gelir ...


1
Genel olarak _id alanını ObjectID türü ile karıştırıyor olabilirsiniz. ObjectID türü, bir UUID gibi ele alınabilmesi amacıyla benzersiz olması için özel olarak tasarlanmıştır. Ancak _id alanı herhangi bir tür olabilir ve yalnızca örneğinizdeki bir dize gibi anahtar için başka türler kullanırsanız tek bir koleksiyondaki benzersizliği garanti eder.
11:18

@mstearn (Nitpick) Bir UUID'nin doğal olarak benzersiz olduğu fikri kusurludur. İyi bir UUID / dizi oluşturma stratejisi, çarpışmayı olası hale getirebilir, ancak jeneratörler arasında mutlak benzersizliği garanti etmek için benzersiz jeneratörleri (örn. Benzersiz konumlar) dikkate alması gerekir . Verilmiş, çoğu o kadar düşük olasılıklar geçerli hiçbir endişe :-) :-) GUID . Bir konu yapar olsa gelip, yerine yeni nesil kimlikleri kopyalama / çoğaltma olduğunu.

1
@pst: MongoDBs ObjectIDs, hem oluşturma işleminin pidini hem de anasistem adının bir karmasını temel alan bazı baytları içerir. Bunlar bir zaman damgası ve artan sayıcı ile birleştirildiğinde, ayrı ayrı oluşturulan iki ObjectID'nin küresel / evrensel olarak benzersiz olmasını büyük olasılıkla mümkün kılar. Tabii ki sadece yeni oluşturulan ObjectIDs için söylediğin gibi.
11:39

1
ObjectId türüne atıfta bulunuyorum. '_İd' için dize değeri belirtmiyor. Elbette aynı olacaklar ve el ile tam olarak aynı dizeye ayarlarsanız çakışacaktır.
Anthony Jack

Evet, görevimdeki şeyleri netleştirdim. _id'ler kesinlikle benzersiz değildir ve ObjectId oluşturma işlevini denetlemediğiniz için, muhtemelen ona güvenmek kötü bir fikirdir.
Slacy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.