Tiếp theo từ phản hồi ban đầu của tôi , đây lại là thứ mà một số suy nghĩ khác có thể giúp bạn. Và như vậy, điều này có vẻ là về kiến trúc hơn là nói rằng việc triển khai mã của bạn "theo một cách nhất định" sẽ là cách tốt nhất để thực hiện.
Từ nhận xét của bạn về điều đó và câu hỏi của bạn ở đây, có vẻ như vấn đề bạn cần giải quyết là làm thế nào để điều chỉnh số lượng quân cho khác người dùng chơi di chuyển. Hãy bắt đầu bằng cách xem lại cùng một dữ liệu:
{ "_id" : ObjectId("531cf5f3ba53b9dd07756bb7"), "user" : "A", "units" : 50 }
{ "_id" : ObjectId("531cf622ba53b9dd07756bb9"), "user" : "B", "units" : 62 }
Thực hiện "di chuyển"
Vì vậy, tình huống ở đây là người dùng "B" vừa thực hiện hành động của họ và cam kết 62
đơn vị trong nước đi đó. Trong bài viết trước, tôi đã giải thích cách lấy lại nước đi cho người dùng phù hợp "A", và do đó bạn có thể "ghép đôi" họ và xác định chiến thắng.
Xa hơn nữa, hãy xem xét điều gì đã xảy ra trong yêu cầu. Người dùng "B" đã gửi, sau đó bạn chèn tài liệu để di chuyển của họ, sau đó bạn đọc lại tài liệu phù hợp. Vì vậy, ngay bây giờ bạn có cả hai tài liệu trong bộ nhớ cho yêu cầu. Nếu bạn xem xét dữ liệu phiên, thì bạn có thể có một cái gì đó như thế này (một cách rất ngắn gọn):
{
currentUnits: 100
}
Hãy gọi đó là số bắt đầu. Vì vậy, khi bạn gửi một động thái từ người dùng, bạn chỉ cần giảm số lượng quân mà họ có. Vì vậy, khi thực hiện chèn trong tổng số 62
quân, bộ đếm đi tới cái này:
{
currentUnits: 38
}
Đó là thực tiễn tốt, khi bạn làm điều đó trên xác nhận chèn trong khi di chuyển. Nhưng tiếp theo bên trong lệnh gọi lại đó, bạn sẽ thực hiện tìm kiếm như tôi đã nói và chỉ trả về một tài liệu. Bây giờ bạn có thông tin bạn có thể so sánh và làm toán của bạn. Người dùng "B" thắng nên bạn có thể điều chỉnh giá trị phiên của mình:
{
currentUnits: 150
}
Vì vậy, điều đó sẽ bao gồm tất cả mọi thứ cho việc di chuyển cho người dùng "B". Bạn lấy đi các đơn vị khi một nước đi được chơi, bạn khớp với người chơi khác, sau đó bạn "làm toán" và điều chỉnh kết quả của mình. Xong! Ồ, và bạn đã tiết kiệm được tất cả dữ liệu phiên trong một cửa hàng liên tục phải không? Gật đầu có. Ngoài ra, dữ liệu phiên đó cũng được gắn với xử lý người dùng (hoặc người dùng trên thực tế là id phiên) để có quyền truy cập vào việc sửa đổi nó.
Tất cả những gì còn lại là "thông báo" cho người chơi khác.
Báo tin tức cho người khác
Phần này phải đơn giản. Vì vậy, tôi không mã hóa nó cho bạn. Bạn đang sử dụng socket.io cho ứng dụng của bạn, vì vậy tất cả những điều này chỉ là gửi một tin nhắn. Điều đó có nghĩa là dữ liệu bạn "phát ra" cho người dùng khác trên máy khách biết rằng họ "mất quân", tuy nhiên bạn muốn xử lý nó như thế nào. Nhưng cũng nên nhớ rằng bạn đã "lấy đi" các đơn vị đó khi di chuyển của chúng đã được gửi. Trong mọi trường hợp đảm bảo rằng không ai có thể cam kết nhiều hơn những gì họ có.
Điều duy nhất có thể nói ở đây là mở rộng quy mô ứng dụng của bạn ngoài một phiên bản. Vì vậy, bạn có thể nói chuyện vui vẻ với các sự kiện trên "nút", tất cả đều hoạt động trên một phiên bản máy chủ, nhưng để "mở rộng quy mô", bạn sẽ cần chuyển thông báo giữa các phiên bản khác nhau.
Một cách để xử lý vấn đề này bằng MongoDB có thể là với bộ sưu tập có giới hạn .
Ngoài những gì các bộ sưu tập có giới hạn thường làm theo cách giữ một tập hợp kích thước cho một bộ sưu tập tài liệu, còn một thứ nữa mà họ cung cấp và đó là con trỏ có thể điều chỉnh . Một cách khá điển hình để tạo một cái bằng trình điều khiển nút sẽ như sau:
var options = { tailable: true, awaitdata: true, numberOfRetries: -1 };
var cursor = collection.find(query, options).sort({ $natural: 1 });
Các tùy chọn đầy đủ được liệt kê trong Con trỏ () phần của trang hướng dẫn sử dụng trình điều khiển. Bạn có thể lấy các phương thức "gốc" này trong mongoose theo cách thông thường.
Con trỏ "có thể điều chỉnh" được thiết lập để làm là "theo dõi" tài liệu "được chèn lần cuối" trong bộ sưu tập và bạn có thể ngồi và "theo dõi" theo cách này với một cuộc thăm dò đồng đều, giống như trong:
(function more() {
cursor.nextObject(handle(function(doc) {
if (!doc) return setTimeout(poll, self.wait);
callback(doc);
latest = doc._id;
more();
}));
})();
Vì vậy, trong một cấu trúc như vậy, bạn "tìm thấy" tài liệu mới được chèn và chuyển đến lệnh gọi lại bên trong của bạn thông tin cần được xử lý, nơi bạn "gửi" tin nhắn cho khách hàng, cập nhật mọi thứ và bất cứ điều gì khác bạn muốn làm.
Quay lại với bạn "yêu cầu" thực tế, sau đó bạn sẽ phát hành một phụ trang sau khi bạn "làm toán" cho "bộ sưu tập có giới hạn" riêng biệt. Bạn muốn điều gì đó có ý nghĩa bằng những câu ngắn gọn như:
{ "player": "B", "vsplayer": "A", "win": 50, "loss": 62 }
Và một lần nữa đây là chỉ phụ trang. Vì vậy, bạn sẽ thiết lập một chỉ mục TTL để xử lý việc xóa theo thời gian và bị giới hạn, các mục cũ sẽ tự nhiên cạn kiệt bằng cách bị "đẩy ra" khỏi các mục có trong bộ sưu tập.
Về phía "khách hàng" của bạn, mỗi ứng dụng người dùng được kết nối sẽ theo dõi giá trị "_id cuối cùng" được khôi phục. Vì vậy, các mục nhập mới được chèn là luôn luôn có giá trị lớn hơn những cái trước "cũ hơn".
Vì vậy, có "một cách" để sử dụng MongoDB để tạo một hàng đợi liên tục mà bạn có thể xử lý tuần tự để chia sẻ thông báo truyền giữa nhiều phiên bản máy chủ ứng dụng.
Lời cuối cùng
Với tất cả những gì đã nói về việc triển khai con trỏ "có thể điều chỉnh" theo cách này, vì tiền của tôi, tôi sẽ sử dụng zeromq hoặc một cái gì đó tương tự. Nhưng bạn có thể thấy phương pháp MongoDB phù hợp với mình hơn nếu bạn không muốn đi sâu vào một công nghệ khác. Hoặc có lẽ ứng dụng của bạn không cần loại "khả năng mở rộng" này (ít nhất là ở giai đoạn này) và chỉ cần chuyển đến các phương thức "socket.io" trong yêu cầu là đủ. Tùy thuộc vào bạn.
Mặc dù vậy, có vẻ như bạn vẫn còn "treo" các khái niệm "cắt" và "xóa" của mình. Đây là ý định đề cập trong phản hồi cuối cùng và muốn nói rằng xóa tài liệu khi chúng được xử lý không bắt buộc . Quy trình được mô tả đảm bảo mà bạn không bao giờ nhận được "cùng một cặp" quay lại bất kỳ yêu cầu nào.
Tôi khuyến khích bạn "đọc lại" thông tin đó và thực sự hiểu quy trình. Và hỏi nếu bạn có câu hỏi. Từ những gì đã được thảo luận ở đó, mô hình truy cập dữ liệu tương tự của bạn giống như "chơi theo một ngăn xếp" hơn là "các cặp phù hợp".
Vì vậy, những gì bạn được cung cấp để đáp lại, tiếp theo trên với logic được mô tả ở đây là tất cả bạn cần để thiết lập các mẫu truy cập dữ liệu của mình. Thành phần khác của bạn tất nhiên sẽ là thông báo, nhưng điều này cho phép bạn truy cập vào dữ liệu mà bạn cần.