2015-09-15 84 views
0

MongoDB比我想起的要难!我已经尝试了各种版本的if-exists-replace-else-insert以及各种功能和选项。它应该很容易,不是吗?使用MongoDB .Net驱动程序查找POCO

这是我个人认为,以下应该工作。

var collection = storageClient.GetCollection<Observer>("observers"); 
await collection.Indexes.CreateOneAsync(Builders<Observer>.IndexKeys.Ascending(_ => _.MyId), new CreateIndexOptions { Unique = true }); 

foreach (var observer in _observers) 
{ 
    observer.Timestamp = DateTime.Now; 

    var res = await collection.FindAsync(o => o.MyId == observer.MyId); 
    if (res==null ||res.Current == null) { 
     await collection.InsertOneAsync(observer); //Part 1, fails 2nd time solved with res.MoveNextAsync() 
    } 
    else 
    { 
      observer.ID = res.Current.Single().ID; 
      var res2 = await collection.ReplaceOneAsync(o=>o.MyId==observer.MyId, observer); 

      var res3 = await collection.FindAsync(o => o.MyId == observer.MyId); 
      await res3.MoveNextAsync(); 
      Debug.Assert(res3.Current.Single().Timestamp == observer.Timestamp); //Part 2, Assert fails. 
    } 
} 

观察看起来大约是这样的:

public class Observer : IObserver 
{ 
    [BsonId] 
    public Guid ID { get; set; } 

    public int MyId { get; set; } 

    public DateTime Timestamp { get; set; } 
} 

我使用完全相同的集合运行此第二次,我意外地得到:

E11000 duplicate key error index: db.observers.$MyId_1 dup key: { : 14040 } 

编辑:

新增原第二部分代码:替换。

编辑2:

现在我的代码看起来像这样。仍然失败。

var collection = storageClient.GetCollection<Observer>("gavagai_mentions"); 
    await collection.Indexes.CreateOneAsync(Builders<Observer>.IndexKeys.Ascending(_ => _.MyID), new CreateIndexOptions { Unique = true }); 
    foreach (var observer in _observers) 
    { 
    observer.Timestamp = DateTime.Now; 

    // Create a BsonDocument version of the POCO that we can manipulate 
    // and then remove the _id field so it can be used in a $set. 
    var bsonObserver = observer.ToBsonDocument(); 
    bsonObserver.Remove("_id"); 

    // Create an update object that sets all fields on an insert, and everthing 
    // but the immutable _id on an update. 
    var update = new BsonDocument("$set", bsonObserver); 
    update.Add(new BsonDocument("$setOnInsert", new BsonDocument("_id", observer.ID))); 

    // Enable the upsert option to create the doc if it's not found. 
    var options = new UpdateOptions { IsUpsert = true }; 
    var res = await collection.UpdateOneAsync(o => o.MyID == observer.MyID, 
          update, options); 


    var res2 = await collection.FindAsync(o => o.MyID == observer.MyID); 
    await res2.MoveNextAsync(); 
    Debug.Assert(res2.Current.Single().Timestamp == observer.Timestamp); //Assert fails, but only because MongoDB stores dates as UTC, or so I deduce. It works!! 
    } 
+0

对于未来的读者来说,文档是在这里:http://mongodb.github.io/mongo-csharp-driver/2.0/reference/driver/crud/reading/#finding-documents –

+0

克雷格谢谢!这实际上很有帮助。这些日子很难在StackOverflow上获得帮助。如果可以的话,请查看第二部分。 http://stackoverflow.com/questions/32586064/replace-poco-with-mongodb-net-driver-2 – Martin

+0

你想要做的事应该能够通过['UpdateOneAsync'](http:/ /api.mongodb.org/csharp/current/html/M_MongoDB_Driver_IMongoCollection_1_UpdateOneAsync.htm?_ga=1.73733265.2070706799.1441907109)与upsert选项来创建文档,如果它没有找到。这样你可以做到这一点原子。你看过吗?你可以将它作为所有字段的“$ set”来构造,以便它能够有效地替换文档(如果找到的话)。 – JohnnyHK

回答

1

如果文档不存在,您可以使用IsUpsert选项创建文档,以UpdateOneAsync自动完成。

foreach (var observer in _observers) 
{ 
    // Create a BsonDocument version of the POCO that we can manipulate 
    // and then remove the _id field so it can be used in a $set. 
    var bsonObserver = observer.ToBsonDocument(); 
    bsonObserver.Remove("_id"); 

    // Create an update object that sets all fields on an insert, and everthing 
    // but the immutable _id on an update. 
    var update = new BsonDocument("$set", bsonObserver); 
    update.Add(new BsonDocument("$setOnInsert", new BsonDocument("_id", observer.ID))); 

    // Enable the upsert option to create the doc if it's not found. 
    var options = new UpdateOptions { IsUpsert = true };  
    var res = await collection.UpdateOneAsync(o => o.MyId == observer.MyId, 
               update, options); 
} 
+0

谢谢,@JohnnyHK。但是:指定了无效的修饰符$ setOnInsert – Martin

+0

['setOnInsert'](http://docs.mongodb.org/manual/reference/operator/update/setOnInsert/#up._S_setOnInsert)在2.4中引入;你的服务器是什么版本? – JohnnyHK

+0

年纪大了。我升级了,效果更好。断言仍然失败,请参阅编辑。 – Martin

0

好的,这是我用光标工作了很长一段时间。

await res.MoveNextAsync(); 

帮助。

这件事对Google来说并不难,但事实是,我失败了,所以我要离开这个问题了。

如果你有第二部分https://stackoverflow.com/questions/32586064/replace-poco-with-mongodb-net-driver-2的答案,那么,真的很想在这里发布,那么我会很高兴两个编辑问题。

正如在评论中指出的那样,信息实际上在文档http://mongodb.github.io/mongo-csharp-driver/2.0/reference/driver/crud/reading/#finding-documents中很容易获得。

+0

我认为问题在于您试图替换ID字段不同的文档。 MongoDB中的ID字段是不可变的,因此不能被替换。因此,当您尝试用另一个文档“替换”一个文档时,其用途是使用相同的标识替换同一个文档。在这种特殊情况下,您最终可能会试图用集合中已经存在的文档替换文档。也许在另一个问题中解释这个问题本身(你想要做什么),而不是引用这个问题会有帮助)。 –

+0

你是指“引用这个”是什么意思?这个问题的混乱,我不知道如何解决所有问题后我将如何清理是由于其他问题被关闭作为这一个副本。他们互相引用。 – Martin

相关问题