Как удалить все документы в DocumentDB через код С#

Я использую новую базу данных от Microsoft под названием DocumentDB. Теперь хочу удалить документ по ID, но не могу понять, как это сделать. Операция удаления в DocumentDB требует собственных ссылок, и они отличаются от моих собственных идентификаторов. Однако я один раз запрашиваю документ, затем я получу ссылку на себя. С помощью этой ссылки я удаляю документ.

Теперь я хочу удалить все документы около 50000+ документов в моей коллекции.

Нужно получить каждый документ, а затем удалить или любой простой способ сделать то же самое?

Возможно ли это?


person satish kumar V    schedule 19.03.2015    source источник
comment
(в java) Я тоже хотел бы удалить весь документ данной коллекции. Кажется невозможным использование синтаксиса SQL. Например, УДАЛИТЬ ОТ ГДЕ сегодня недоступно. Я голосую за этот отзыв, который находится в состоянии under review. Я не хочу удалять повторное создание родительской коллекции: для меня это неприемлемый обходной путь. Я был бы очень рад получить решение для этого...   -  person boly38    schedule 06.07.2015
comment
Ссылку на этот вопрос можно увидеть, если вы экспортируете шаблон экземпляра Azure Cosmos DB!   -  person Sunil Purushothaman    schedule 10.03.2020


Ответы (3)


Вы правы, что для удаления документов требуется ссылка на документ _self.

Если вы хотите удалить ВСЕ документы в своей коллекции, возможно, будет проще и быстрее удалить и заново создать коллекцию. Единственное предостережение заключается в том, что скрипты на стороне сервера (например, sprocs, udfs, триггеры) также относятся к коллекции и, возможно, их также необходимо создать заново.

Обновление: я написал быструю хранимую процедуру, которая выполняет массовое удаление по запросу. Это позволяет выполнять операции массового удаления с меньшим количеством сетевых запросов.

/**
 * A DocumentDB stored procedure that bulk deletes documents for a given query.<br/>
 * Note: You may need to execute this sproc multiple times (depending whether the sproc is able to delete every document within the execution timeout limit).
 *
 * @function
 * @param {string} query - A query that provides the documents to be deleted (e.g. "SELECT * FROM c WHERE c.founded_year = 2008")
 * @returns {Object.<number, boolean>} Returns an object with the two properties:<br/>
 *   deleted - contains a count of documents deleted<br/>
 *   continuation - a boolean whether you should execute the sproc again (true if there are more documents to delete; false otherwise).
 */
function bulkDeleteSproc(query) {
    var collection = getContext().getCollection();
    var collectionLink = collection.getSelfLink();
    var response = getContext().getResponse();
    var responseBody = {
        deleted: 0,
        continuation: true
    };

    // Validate input.
    if (!query) throw new Error("The query is undefined or null.");

    tryQueryAndDelete();

    // Recursively runs the query w/ support for continuation tokens.
    // Calls tryDelete(documents) as soon as the query returns documents.
    function tryQueryAndDelete(continuation) {
        var requestOptions = {continuation: continuation};

        var isAccepted = collection.queryDocuments(collectionLink, query, requestOptions, function (err, retrievedDocs, responseOptions) {
            if (err) throw err;

            if (retrievedDocs.length > 0) {
                // Begin deleting documents as soon as documents are returned form the query results.
                // tryDelete() resumes querying after deleting; no need to page through continuation tokens.
                //  - this is to prioritize writes over reads given timeout constraints.
                tryDelete(retrievedDocs);
            } else if (responseOptions.continuation) {
                // Else if the query came back empty, but with a continuation token; repeat the query w/ the token.
                tryQueryAndDelete(responseOptions.continuation);
            } else {
                // Else if there are no more documents and no continuation token - we are finished deleting documents.
                responseBody.continuation = false;
                response.setBody(responseBody);
            }
        });

        // If we hit execution bounds - return continuation: true.
        if (!isAccepted) {
            response.setBody(responseBody);
        }
    }

    // Recursively deletes documents passed in as an array argument.
    // Attempts to query for more on empty array.
    function tryDelete(documents) {
        if (documents.length > 0) {
            // Delete the first document in the array.
            var isAccepted = collection.deleteDocument(documents[0]._self, {}, function (err, responseOptions) {
                if (err) throw err;

                responseBody.deleted++;
                documents.shift();
                // Delete the next document in the array.
                tryDelete(documents);
            });

            // If we hit execution bounds - return continuation: true.
            if (!isAccepted) {
                response.setBody(responseBody);
            }
        } else {
            // If the document array is empty, query for more documents.
            tryQueryAndDelete();
        }
    }
}
person Andrew Liu    schedule 19.03.2015
comment
Ага, я тоже так подумал. Если я удаляю коллекцию, мне нужно снова создавать хранимые процедуры и триггеры. Но в любом случае, спасибо, что сообщили мне, что нет другого простого процесса для одновременного удаления всех записей :) - person satish kumar V; 20.03.2015
comment
проголосовать против: нет ответа на этот вопрос: спасибо, дайте мне знать, что нет другого простого процесса для удаления всех записей сразу - person boly38; 06.07.2015
comment
К сведению: голосование должно основываться на том, получите ли вы точный ответ на вопрос... а не на том, поддерживает ли используемое вами программное обеспечение какую-либо функцию. - person Andrew Liu; 11.12.2015
comment
Здравствуйте @andrew-liu. Использование sproc позволяет мне выполнять операции массового удаления с меньшим количеством сетевых запросов, но это не влияет на оплачиваемые единицы запросов. Я прав? Каждое выполнение sproc (кроме первого) в моем случае регулируется, а рекомендуемый интервал времени повтора действительно высок (10 секунд !!!) и имеет очень высокие затраты на единицу запроса. Похоже, что взимаемые единицы запроса равны или даже выше с этой sproc, в отличие от запроса на удаление для каждого документа, и из-за дросселирования я не вижу никаких преимуществ в производительности при использовании этой sproc. Действительно раздражает! - person Tobias J.; 28.07.2016
comment
@Тобиас Дж. Я согласен с вашими мыслями, возможно, вы могли бы использовать функциональность TimeToLive. Я полагаю, что это будет гораздо более дешевая операция. Это обновление для каждого документа, который вы хотите удалить, и DocumentDB очистит их в фоновом режиме. Я полагаю, что DocumentDB не взимает плату за удаление, но, очевидно, будет взимать плату за ваше обновление. - person SimonGates; 07.10.2016
comment
использование store proc работает только тогда, когда ваша коллекция одиночная, если раздел я не знаю, как это сделать - person Grey Wolf; 30.01.2018

Вот решение для удаления документов с помощью C# SDK. В приведенном ниже коде предполагается одна база данных и одна коллекция. Он будет перебирать все документы в коллекции и удалять их по одному. Чтобы удалить определенные базы данных, коллекции или документы, измените соответствующий метод «CreateQuery», включив в него синтаксис выбора SQL. Например, чтобы выбрать конкретную базу данных,

db = client.CreateDatabaseQuery().Where(o => o.Id == "MyDocDb").ToList().First();

Пример кода для удаления всех документов в экземпляре DocumentDB с одной базой данных и одной коллекцией:

using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Documents.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Util
{
    class Program
    {
        private Uri _docDbUri = new Uri("https://<nameofyourdocdb>.documents.azure.com:443/");
        private string _docDbKey = "<your primary key>";

        private async Task DeleteDocsAsync()
        {
            using (var client = new DocumentClient(_docDbUri, _docDbKey))
            {
                try
                {
                    var db = client.CreateDatabaseQuery().ToList().First();
                    var coll = client.CreateDocumentCollectionQuery(db.CollectionsLink).ToList().First();
                    var docs = client.CreateDocumentQuery(coll.DocumentsLink);
                    foreach (var doc in docs)
                    {
                        await client.DeleteDocumentAsync(doc.SelfLink);
                    }
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex);
                    throw;
                }
            }
        }



        static void Main(string[] args)
        {
            try
            {
                Program p = new Program();
                p.DeleteDocsAsync().Wait();
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}
person Brett    schedule 11.11.2015
comment
Это метод получения всех записей и их удаления по одной. Спасибо за ответ. - person satish kumar V; 13.11.2015
comment
Этот метод требует изменения, для вызова DeleteDocumentAsync требуется ключ секции как часть объекта RequestOptions. Кроме этого, это действительно помогло. Спасибо. - person Yatin; 26.09.2016
comment
сохранение всех задач в список, а затем ожидание их всех, вероятно, сэкономит время. или даже каждую партию из 100, если коллекция огромна. - person Ram Y; 19.07.2017
comment
Я не верю, что это сработает для удаления всех документов для секционированной коллекции, поскольку хранимые процедуры не могут выполняться между секциями. - person sirdank; 17.12.2018

Вот способ удалить документы с включенным AllowBulkExecution. Этот метод удаляет документы частями по 100, так как в настоящее время Cosmos DB поддерживает не более 100 операций одновременно. Он принимает имя свойства ключа раздела и использует отражение для получения его значения.

public async Task BulkDeleteDocumentsAsync(IEnumerable<T> entities, string partitionKeyPropertyName)
    {
        List<Task> tasks = new List<Task>(100);
        foreach (var entity in entities)
        {
            var partitionKey = entity.GetType().GetProperty(partitionKeyPropertyName)?.GetValue(entity, null)?.ToString();
            if (partitionKey != null)
            {
                tasks.Add(DeleteDocumentAsync(entity.Id!, partitionKey)
                    .ContinueWith(itemResponse =>
                    {
                        if (!itemResponse.IsCompletedSuccessfully)
                        {
                            AggregateException innerExceptions = itemResponse.Exception!.Flatten();

                            if (innerExceptions.InnerExceptions.FirstOrDefault(innerEx => innerEx is CosmosException) is CosmosException cosmosException)
                            {
                                _logger.LogError($"Cosmos Exception deleting {entity.Id} {cosmosException.StatusCode} ({cosmosException.Message}).");
                            }
                            else
                            {
                                _logger.LogError($"Exception deleting {entity.Id} {innerExceptions.InnerExceptions.FirstOrDefault()}.");
                            }
                        }
                    }));
                if (tasks.Count == 100)
                {
                    await Task.WhenAll(tasks);
                    tasks.Clear();
                }
            }
        }
        await Task.WhenAll(tasks);
    }
person Roman Svitukha    schedule 25.05.2021