Raven DB:如何删除特定类型的所有文档

17

更具体地说,在 Raven DB 中,我想创建一个带有如下签名的通用方法:

public void Clear<T>() {...

然后让 Raven DB 清除所有给定类型的文档。

我从 Ayende 的其他类似问题的帖子中了解到,您需要先建立索引才能作为批处理执行此操作。

我认为这将涉及创建一个将每种文档类型映射到其自身的索引 - 这似乎是很费力的。

有没有人知道一种高效的方法来创建像上面那样直接在数据库中进行集合删除的方法?

4个回答

23

我假设您希望从.NET客户端执行此操作。如果是这样,请使用标准DocumentsByEntityName索引:

var indexQuery = new IndexQuery { Query = "Tag:" + collectionName };
session.Advanced.DocumentStore.DatabaseCommands.DeleteByIndex(
   "Raven/DocumentsByEntityName", 
   indexQuery, 
   new BulkOperationOptions { AllowStale = true });

var hilo = session.Advanced.DocumentStore.DatabaseCommands.Get("Raven/H‌​ilo/", collectionName);
if (hilo != null) {
    session.Advanced.DocumentStore.DatabaseCommands.Delete(hilo.‌​Key, hilo.Etag);
}

其中collectionName是你的集合的实际名称。

第一个操作删除项目,第二个操作删除HiLo文件

此外,请参阅官方文档-如何使用索引删除或更新文档


1
这是我个人认为更好的方法,因为它不需要创建索引,并且删除任何可能未包含在现有索引中的文档。 - wal
我也喜欢删除相关的 HiLo 文档以重置 ID。@alexn,我可以编辑你的代码来添加这个吗?var hilo = session.Advanced.DocumentStore.DatabaseCommands.Get("Raven/Hilo/themes"); session.Advanced.DocumentStore.DatabaseCommands.Delete(hilo.Key, hilo.Etag); - SandRock
@SandRock 当然可以 :) - alexn
以上代码存在一些语法错误。这里是没有错误的代码: var indexQuery = new IndexQuery { Query = "Tag:" + collectionName }; session.Advanced.DocumentStore.DatabaseCommands.DeleteByIndex( "Raven/DocumentsByEntityName", indexQuery, new BulkOperationOptions { AllowStale = true }); var hilo = session.Advanced.DocumentStore.DatabaseCommands.Get("Raven/H‌​ilo/" + collectionName); if (hilo != null) { session.Advanced.DocumentStore.DatabaseCommands.Delete(hilo.Key, hilo.Etag); } - Sajid Ali

9

经过许多实验,我发现答案非常简单,尽管远非显而易见;

public void Clear<T>()
{
    session.Advanced.DocumentStore.DatabaseCommands.PutIndex(indexName, new IndexDefinitionBuilder<T>
    {
        Map = documents => documents.Select(entity => new {})
    });

    session.Advanced.DatabaseCommands.DeleteByIndex(indexName, new IndexQuery());
}

当然,你几乎肯定不会一次性定义索引并执行删除操作,我将其作为单个方法出于简洁的考虑。
我的实现遵循文档建议,在应用程序启动时定义索引。
如果您想使用这种方法来实际索引T的属性,则需要约束T。例如,如果我有一个IEntity,所有我的文档类都继承自该类,并且该类指定一个属性Id。那么“where T:IEntity”将允许您在索引中使用该属性。
其他地方已经说过,但值得注意的是,一旦您定义了静态索引,Raven就可能会使用它,这可能导致您的查询似乎没有返回您插入的数据: RavenDB Saving to disk query

2
作为RavenDB的贡献者,我不建议这种方式,因为你是在无谓地创建一个索引。相反,我推荐@alexn的答案:https://dev59.com/dGkw5IYBdhLWcg3wGGm8#13049179 - Judah Gabriel Himango

8

我也遇到过这个问题,以下是解决方法。我只在一个测试项目中使用,所以对于更大的数据库可能会慢一些,但Ryan的答案对我没有起作用。

    public static void ClearDocuments<T>(this IDocumentSession session)
    {
        var objects = session.Query<T>().ToList();
        while (objects.Any())
        {
            foreach (var obj in objects)
            {
                session.Delete(obj);
            }

            session.SaveChanges();
            objects = session.Query<T>().ToList();
        }
    }

我还在对嵌入式存储运行测试,只有你的解决方案对我有效。Google Groups(https://groups.google.com/forum/#!topic/ravendb/QqZPrRUwEkE)上的一篇帖子建议在这种情况下首先创建DocumentsByEntityName索引:“new RavenDocumentsByEntityName().Execute(store);” 尽管我已经这样做了,但我仍然发现应该被删除的文档仍然存在(我还防止返回陈旧的查询,所以这也不是答案)。 - rogersillito

4

嗨,Ayende,你的回答真的很有用,但并不完全是我想要的。经过许多实验和学习Raven,我找到了我想要的解决方案。我很快会在这里发布答案供其他人参考。 - Ryan Worsley
我发现这是最简单的非编程解决方案。 - Keith
我在那篇博客中没有找到提到重置命令的内容。最终得到了类似Ryan的索引。 - Nils Magne Lunde

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接