简体   繁体   English

如何通过GUID _id查找文档?

[英]How can I find a document by GUID _id?

I use this code to retrieve some documents: 我使用此代码来检索一些文档:

var client = new MongoClient(connectionString);
var database = client.GetDatabase(databaseName);
var collection = database.GetCollection<BsonDocument>(collectionName);

var json = "{created: {$gte: ISODate(\"2018-12-20T00:00:00.000Z\"), $lt: 
ISODate(\"2018-12-21T00:00:00.000Z\")}}";
BsonDocument query = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>(json);
var documents = collection.Find(query).Limit(10);

The results look like this: 结果如下所示:

{ "_id" : CSUUID("75c5634c-b64b-4484-81f5-5b213228e272"), ..., "created" : ISODate("2018-12-20T23:59:13.375Z") }

I'm having trouble retrieving this same document when trying to filter on _id. 在尝试过滤_id时,我在检索同一文档时遇到问题。 Here are the filters I've tried (using the same code as above) and have not been able to retrieve the document: 以下是我尝试过的过滤器(使用与上面相同的代码)并且无法检索文档:

var json = "{ \"_id\" : \"75c5634c-b64b-4484-81f5-5b213228e272\" }";
var json = "{ \"_id\" : CSUUID(\"75c5634c-b64b-4484-81f5-5b213228e272\") }";
var json = "{ \"_id\" : new BinData(4, \"TGPFdUu2hESB9VshMijicg==\") }";
var json = "{ \"_id\" : BinData(4, \"TGPFdUu2hESB9VshMijicg==\") }";
var json = "{ \"_id\" : new BinData(3, \"TGPFdUu2hESB9VshMijicg==\") }";
var json = "{ \"_id\" : BinData(3, \"TGPFdUu2hESB9VshMijicg==\") }";
var json = "{ \"_id\" : { $eq: \"TGPFdUu2hESB9VshMijicg==\" } }";
var json = "{ \"_id\" : { $binary: \"TGPFdUu2hESB9VshMijicg==\", $type: 4 } }";
var json = "{ \"_id\" : { $binary: \"TGPFdUu2hESB9VshMijicg==\", $type: 3 } }";

Note, TGPFdUu2hESB9VshMijicg== was retrieved by getting a base 64 encoded string from the guid like this: 注意,通过从guid获取base 64编码的字符串来检索TGPFdUu2hESB9VshMijicg== ,如下所示:

Convert.ToBase64String((new Guid("75c5634c-b64b-4484-81f5-5b213228e272")).ToByteArray())

None of the queries throw any exceptions, but they return no documents. 没有任何查询抛出任何异常,但它们不返回任何文档。

Adding this before even creating MongoClient() resolved the issue for me: 在创建MongoClient()之前添加它解决了我的问题:

BsonDefaults.GuidRepresentation = GuidRepresentation.Standard;

It looks like on the C# side the MongoDB driver was interpreting it as a UUID with a binary subtype of 3. However, the documents saved in the collection had a binary subtype of 4. 看起来在C#端,MongoDB驱动程序将其解释为具有二进制子类型3的UUID。但是,保存在集合中的文档具有4的二进制子类型。

Also, after this change the document retrieved shows "UUID()" rather than "CSUUID()": 此外,在此更改后,检索到的文档显示“UUID()”而不是“CSUUID()”:

{ "_id" : UUID("75c5634c-b64b-4484-81f5-5b213228e272"), ..., "created" : ISODate("2018-12-20T23:59:13.375Z") }

After more time than I'd care to admit searching the web and testing many theories, the breakthrough came from skimming through this article: https://www.codeproject.com/Articles/987203/%2FArticles%2F987203%2FBest-Practices-for-GUID-data-in-MongoDB 经过一段时间,我不得不承认在网上搜索和测试许多理论,这一突破来自于浏览这篇文章: https : //www.codeproject.com/Articles/987203/%2FArticles%F987203%2FBest-Practices-换GUID数据功能于MongoDB中

Excerpt from that link: 摘自该链接:

MongoDB drivers usually store UUIDs as Binary fields with the legacy 0x03 subtype assigned by default. MongoDB驱动程序通常将UUID存储为二进制字段,默认情况下分配旧的0x03子类型。 This configuration can be changed: 此配置可以更改:

C#: C#:

You can override the driver's default settings and configure it to use the Binary 0x04 subtype by modifying the value of BsonDefaults.GuidRepresentation: 您可以通过修改BsonDefaults.GuidRepresentation的值来覆盖驱动程序的默认设置并将其配置为使用二进制0x04子类型:

 BsonDefaults.GuidRepresentation = GuidRepresentation.Standard; 

You can also modify GuidRepresentation at the server, database and collection level. 您还可以在服务器,数据库和集合级别修改GuidRepresentation。

EDIT: 编辑:

This is what I ended up using for the json filter: 这就是我最终用于json过滤器的内容:

var json = "{ \"_id\" : UUID(\"75c5634c-b64b-4484-81f5-5b213228e272\") }";

The MongoDb C# driver does a lot of work trying to keep you away of the Json (Bson) representation. MongoDb C#驱动程序做了很多工作,试图让你远离Json(Bson)表示。 To oversimplify, you have 3 ways of working with MongoDb with C# 为了过度简化,您有3种方式使用C#使用MongoDb

  • use raw Json (which is very "server-side" progamming). 使用原始Json(这是非常“服务器端”编程)。
  • use the Swiss army knife BsonDocument class. 使用瑞士军刀BsonDocument类。
  • use typed C# classes. 使用键入的C#类。

And of course, a combination of the 3, which makes things much worse :-) 当然,3的组合,这使事情更糟:-)

So, in your case, here is how you would do the BsonDocument way (w/o any JSON): 所以,在你的情况下,这里是你如何做BsonDocument方式(没有任何JSON):

var client = new MongoClient(myConnectionString);
var db = client.GetDatabase("myDb");
var guid = Guid.NewGuid();

// create an untyped document
var doc = new BsonDocument { { "_id", guid } };
var coll = db.GetCollection<BsonDocument>("myColl");
coll.InsertOne(doc);

// Builders<T> is central to help you build all sorts of mongodb JSON jargon (filters, sort, projections, etc.)
// instead of building it by yourself
var filter = Builders<BsonDocument>.Filter.Eq(new StringFieldDefinition<BsonDocument, Guid>("_id"), guid);
var foundDoc = coll.Find(filter).FirstOrDefault();
Console.WriteLine(foundDoc["_id"]);

And here is how you could do the typed-document way (w/o any JSON and w/o any BsonDocument): 以下是如何使用类型文档方式(没有任何JSON和没有任何BsonDocument):

var client = new MongoClient(myConnectionString);
var db = client.GetDatabase("myDb");
var guid = Guid.NewGuid();

// create a class
var doc = new MyDoc { Id = guid };
var coll = db.GetCollection<MyDoc>("myColl");
coll.InsertOne(doc);

// we use a type that correspond to our busines layer/logic
// that's the easier way because you can use Linq syntax so we're far from JSON and document issues
// plus it's super readable in C#
var foundDoc = coll.Find(d => d.Id == guid).FirstOrDefault();
Console.WriteLine(foundDoc.Id);
...

// the typed-document (class)
class MyDoc
{
    [BsonId]
    public Guid Id { get; set; }

    ... other properties...
}

As you see, the last way is much simpler, but we can't always use it. 如您所见,最后一种方法更简单,但我们不能总是使用它。 BTW, it's sad that the driver doesn't allow to derive MyDoc from BsonDocument , because we would truly have best of both worlds (it compiles but throws.... if MongoDb C# devs read this...) 顺便说一句,令人遗憾的是,驱动程序不允许从BsonDocument派生MyDoc ,因为我们真的会拥有两个世界中最好的(它编译但抛出......如果MongoDb C#devs读到这个......)

Now, concerning guids, you'll note the Console.WriteLine(foundDoc["_id"]) displays UuidLegacy:0x87fa981983de774b998868046e257b19 because MongoDb has a legacy history with guids. 现在,关于guids,你会注意到Console.WriteLine(foundDoc["_id"])显示UuidLegacy:0x87fa981983de774b998868046e257b19因为MongoDb有guid的遗留历史记录。

As you found out, you can change BsonDefaults.GuidRepresentation . 如您BsonDefaults.GuidRepresentation ,您可以更改BsonDefaults.GuidRepresentation By default it's CSharpLegacy . 默认情况下,它是CSharpLegacy

Here is a list of prefixes used when guids are displayed as strings throughout code (client or server): 以下是guids在整个代码(客户端或服务器)中显示为字符串时使用的前缀列表:

  • UUID: the standard one ( not legacy) UUID:标准的( 不是遗留的)
  • LUUID: the legacy one (only seen on server) LUUID:遗留的(仅在服务器上看到)
  • CSUUID: the C# legacy one (only seen on clients) CSUUID:C#遗留版(仅在客户端上看到)
  • JUUID: the Java legacy one (only seen on clients) JUUID:Java遗留者(仅在客户端上看到)
  • PYUUID : the Python legacy one (only seen on clients) PYUUID:Python遗留者(仅在客户端上看到)

The 2 and 3 approaches also shield you from these "internal" MongoDb issues. 2和3方法也可以保护您免受这些“内部”MongoDb问题的影响。 If you use these, you don't have to change BsonDefaults.GuidRepresentation . 如果您使用这些, 则无需更改BsonDefaults.GuidRepresentation

So my advise is try to stay away from Json when programming MongoDb with C#. 因此,我建议在使用C#编写MongoDb时远离Json。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM