2017-10-11 32 views
11

Với cơ sở dữ liệu thời gian thực Firebase, chúng tôi có thể xóa một danh sách lớn các mục chỉ bằng một lệnh đơn giản bằng cách gọi remove() trên nút cha (nút bị xóa và tất cả đều là trẻ em).Tại sao bộ sưu tập xóa "một lượng lớn" trong Cloud Firestore không thể thực hiện được như với Cơ sở dữ liệu thời gian thực?

Tuy nhiên, theo tài liệu với FireStore (https://firebase.google.com/docs/firestore/manage-data/delete-data#collections):
để xóa một Bộ sưu tập chúng ta phải mã hóa một lô mà sẽ để lặp qua tất cả các tài liệu của nó và xóa chúng từng cái một.

Điều này không hiệu quả chút nào. Có phải vì Firestore đang ở phiên bản beta hay không, cấu trúc không thể xóa toàn bộ nút (Bộ sưu tập) trong một cuộc gọi đơn lẻ?

Trả lời

11

RTDB có thể thực hiện việc này vì mỗi cơ sở dữ liệu là cục bộ cho một vùng duy nhất. Để cung cấp chế độ xem được tuần tự hóa, khi bạn gọi remove(), cơ sở dữ liệu sẽ dừng tất cả công việc khác cho đến khi việc xóa hoàn tất.

Hành vi này đã là nguyên nhân của một số mất điện rõ ràng: nếu cuộc gọi remove() phải xóa dữ liệu khổng lồ, tất cả hoạt động khác sẽ bị khóa hiệu quả cho đến khi hoàn thành. Kết quả là ngay cả đối với những người dùng RTDB muốn xóa một lượng lớn dữ liệu, chúng tôi đã đề nghị đệ quy tìm và xóa tài liệu theo nhóm. Mặt khác, Firestore dựa trên cơ sở hạ tầng lưu trữ theo phong cách truyền thống của Google, nơi các phạm vi khóa khác nhau được gán dynamically to different servers (bộ nhớ không thực sự được BigTable hỗ trợ, nhưng cũng áp dụng các nguyên tắc tương tự). Điều này có nghĩa rằng việc xóa dữ liệu không còn là một hành động đơn lẻ nhất định và nó trở nên rất tốn kém để thực hiện việc xóa một cách hiệu quả giao dịch. Các giao dịch Firestore hiện bị giới hạn ở 100 người tham gia và điều này có nghĩa là bất kỳ việc xóa hàng loạt giao dịch không tầm thường nào là không thể.

Chúng tôi đang điều tra cách tốt nhất để hiển thị API thực hiện xóa hàng loạt mà không có hành vi giao dịch đầy hứa hẹn. Thật đơn giản để tưởng tượng làm thế nào để làm điều này từ một khách hàng điện thoại di động, nhưng như bạn đã quan sát thấy điều này sẽ không hiệu quả nếu tất cả những gì chúng tôi làm là nhúng vòng lặp và xóa hàng loạt cho bạn. Chúng tôi cũng không muốn làm cho khách hàng REST trở thành công dân hạng hai.

Firestore là sản phẩm mới và vẫn còn nhiều việc phải làm. Thật không may điều này chỉ không thực hiện việc cắt giảm. Mặc dù đây là điều chúng tôi hy vọng sẽ giải quyết cuối cùng nhưng tôi không thể cung cấp bất kỳ thời gian nào về thời điểm đó.

Trong khi chờ đợi, bảng điều khiển và firebase command-line đều cung cấp phương tiện không giao dịch để thực hiện việc này, ví dụ: để tự động hóa thử nghiệm.

Cảm ơn sự thông cảm của bạn và cảm ơn bạn vì đã thử Firestore!

+0

Tôi nghĩ rằng ví dụ trong tài liệu Firestore (được liên kết bởi @toofoo trong câu hỏi) là không chính xác. ´resolve() ´ nên được gọi khi ´ (numDeleted == 0) ´. – Leo

+0

BTW, tải lên hiện tại có được thực hiện theo lô không? Hoặc các giao dịch có thể được sử dụng? – Leo

+0

Và một câu hỏi khác. Bạn đã viết "xóa hàng loạt mà không có hành vi giao dịch đầy hứa hẹn". Tôi cần hành vi giao dịch. Tôi có thể hy vọng điều đó không? – Leo

1

Tôi đã vui vẻ tái cấu trúc ứng dụng của mình cho Firestore từ Cơ sở dữ liệu thời gian thực, tận hưởng mã ngắn hơn và cú pháp đơn giản hơn, cho đến khi tôi tái cấu trúc các hàm delete()! Để xóa tài liệu có các phần con:

  • Tạo một loạt các lời hứa.
  • get() một phần con, không có bộ sưu tập con.
  • Lặp lại thông qua hàm forEach() để đọc từng tài liệu trong phần con.
  • Xóa từng tài liệu và đẩy lệnh xóa vào dãy lời hứa.
  • Chuyển đến phần con tiếp theo và lặp lại điều này.
  • Sử dụng Promise.all(arrayOfPromises) để đợi cho đến khi tất cả các bộ sưu tập con đã bị xóa.
  • Sau đó, xóa tài liệu cấp cao nhất.

Với lớp đa của bộ sưu tập và tài liệu mà bạn sẽ muốn chắc rằng một chức năng, sau đó gọi nó là từ chức năng khác để có được những lớp cao hơn tiếp theo vv

Bạn có thể thấy điều này trong giao diện điều khiển. Để xóa bộ sưu tập và tài liệu theo cách thủ công, hãy xóa tài liệu ngoài cùng bên phải, sau đó xóa bộ sưu tập phù hợp nhất, v.v.

Đây là mã của tôi, trong AngularJS. Nó chỉ hoạt động nếu bộ sưu tập cấp cao nhất không bị xóa trước các bộ sưu tập con.

$scope.deleteClip = function(docId) { 
if (docId === undefined) { 
docId = $scope.movieOrTvShow + '_' + $scope.clipInMovieModel; 
} 
$scope.languageVideos = longLanguageFactory.toController($scope.language) + 'Videos'; 
var promises = []; 
firebase.firestore().collection($scope.languageVideos).doc($scope.movieOrTvShow).collection('Video Clips').doc(docId).collection('SentenceTranslations').get() 
.then(function(translations) { 
    translations.forEach(function(doc) { 
    console.log(doc.id); 
    promises.push(firebase.firestore().collection($scope.languageVideos).doc($scope.movieOrTvShow).collection('Video Clips').doc(docId).collection('SentenceTranslations').doc(doc.id).delete()); 
    }); 
}); 
firebase.firestore().collection($scope.languageVideos).doc($scope.movieOrTvShow).collection('Video Clips').doc(docId).collection('SentenceExplanations').get() 
.then(function(explanations) { 
    explanations.forEach(function(doc) { 
    console.log(doc.id); 
    promises.push(firebase.firestore().collection($scope.languageVideos).doc($scope.movieOrTvShow).collection('Video Clips').doc(docId).collection('SentenceExplanations').doc(doc.id).delete()); 
    }); 
}); 
Promise.all(promises).then(function() { 
    console.log("All subcollections deleted."); 
    firebase.firestore().collection($scope.languageVideos).doc($scope.movieOrTvShow).collection('Video Clips').doc(docId).delete() 
    .then(function() { 
    console.log("Collection deleted."); 
    $scope.clipInMovieModel = null; 
    $scope.$apply(); 
    }) 
    .catch(function(error) { 
    console.log("Remove failed: " + error.message); 
    }); 
}) 
.catch(function(error){ 
    console.log("Error deleting subcollections: " + error); 
}); 
}; 

Tất cả những gì có thể là một dòng trong Cơ sở dữ liệu thời gian thực.

Các vấn đề liên quan