MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Łatwiejszy sposób na aktualizację tablicy za pomocą MongoDB

Jeśli "zależy Ci" na dodaniu tutaj trochę większej funkcjonalności (bardzo zalecane) i ograniczeniu narzutu na aktualizacje, gdzie naprawdę nie musisz zwracać zmodyfikowanego dokumentu, a nawet jeśli to zrobisz, zawsze lepiej jest użyć operatorów atomowych z tablicami takimi jak $push i $addToSet .

„Dodatkowa funkcjonalność” polega również na tym, że podczas używania tablic w pamięci masowej, naprawdę mądrą praktyką jest przechowywanie „długości” lub „liczby” elementów. Staje się to przydatne w zapytaniach i można uzyskać do nich wydajny dostęp za pomocą „indeksu”, w przeciwieństwie do innych metod uzyskiwania „liczby” z tablicy lub używania tej „liczby/długości” do celów filtrowania.

Lepszą konstrukcją jest tutaj użycie operacji „Bulk” ponieważ testowanie obecnych elementów tablicy nie miesza się dobrze z koncepcją „upserts”, więc tam, gdzie potrzebujesz funkcji upsert, testowanie tablicy jest lepsze w dwóch operacjach. Ale ponieważ operacje „zbiorcze” mogą być wysyłane do serwera za pomocą „jednego żądania” i otrzymujesz również „jedną odpowiedź”, zmniejsza to wszelkie realne koszty.

var bulk = FollowModel.collection.initializeOrderedBulkOp();

// Try to add where not found in array
bulk.find({ 
    "facebookId": req.user.facebookId,
    "players": { "$ne": req.body.idToFollow }
}).updateOne({
    "$push": { "players": req.body.idToFollow },
    "$inc": { "playerCount": 1 }
});

// Otherwise create the document if not matched
bulk.find({
    "facebookId": req.user.facebookId,
}).upsert().updateOne({
    "$setOnInsert": {
        "players": [req.body.idToFollow]
        "playerCount": 1,
        "fans": [],
        "fanCount": 0
    }
})

bulk.execute(function(err,result) {
    // Handling in here
});

Sposób, w jaki to działa, polega na tym, że pierwsza próba próbuje znaleźć dokument, w którym element tablicy, który ma zostać dodany, nie znajduje się już w tablicy. W tym miejscu nie jest podejmowana żadna próba „upsert”, ponieważ nie chcesz tworzyć nowego dokumentu, jeśli jedynym powodem, dla którego nie pasuje on do dokumentu, jest brak elementu tablicy. Jeśli jednak zostanie dopasowany, nowy element członkowski jest dodawany do tablicy, a bieżąca „liczba” jest „zwiększana” o 1 za pośrednictwem $inc , który zachowuje całkowitą liczbę lub długość.

Dlatego druga instrukcja będzie pasować tylko do dokumentu i dlatego używa „upsert”, ponieważ jeśli dokument nie zostanie znaleziony dla pola klucza, zostanie utworzony. Ponieważ wszystkie operacje znajdują się w $setOnInsert wtedy nie zostanie wykonana żadna operacja, jeśli dokument już istnieje.

To wszystko jest tak naprawdę jednym żądaniem i odpowiedzią serwera, więc nie ma "tam iz powrotem" dla włączenia dwóch operacji aktualizacji, co czyni to wydajnym.

Usunięcie wpisu w tablicy jest w zasadzie odwrotne, z tym wyjątkiem, że tym razem nie ma potrzeby "tworzenia" nowego dokumentu, jeśli nie został znaleziony:

var bulk = FollowModel.collection.initializeOrderedBulkOp();

// Try to remove where found in array
bulk.find({ 
    "facebookId": req.user.facebookId,
    "players": req.body.idToFollow
}).updateOne({
     "$pull": { "players": req.body.idToFollow },
     "$inc": { "playerCount": -1 }
});

bulk.execute(function(err,result) {
    // Handling in here
});

Teraz wystarczy tylko sprawdzić, gdzie znajduje się element tablicy i gdzie się znajduje $pull dopasowany element z zawartości tablicy, jednocześnie „zmniejszając” „liczbę” o 1, aby odzwierciedlić usunięcie.

Teraz "możesz" użyć $addToSet zamiast tego tutaj, ponieważ po prostu spojrzy na zawartość tablicy i jeśli element nie zostanie znaleziony, zostanie dodany, i z tych samych powodów nie ma potrzeby testowania elementu tablicy istniejącego przy użyciu $pull ponieważ po prostu nic nie zrobi, jeśli elementu nie ma. Ponadto $addToSet w tym kontekście mogą być używane bezpośrednio w "upsert", o ile nie "przecinają się ścieżki", ponieważ nie wolno próbować używać wielu operatorów aktualizacji na tej samej ścieżce z MongoDB:

FollowModel.update(
    { "facebookId": req.user.facebookId },
    {
        "$setOnInsert": {
            "fans": []
        },
        "$addToSet": { "players": req.body.idToFollow }
    },
    { "upsert": true },
    function(err,numAffected) {
        // handling in here
    }
);

Ale byłoby to „niewłaściwe”:

FollowModel.update(
    { "facebookId": req.user.facebookId },
    {
        "$setOnInsert": {
            "players": [],              // <-- This is a conflict
            "fans": []
        },
        "$addToSet": { "players": req.body.idToFollow }
    },
    { "upsert": true },
    function(err,numAffected) {
        // handling in here
    }
);

Jednak robiąc to, tracisz funkcję "liczenia", ponieważ takie operacje są po prostu kończone bez względu na to, co faktycznie tam jest lub czy coś zostało "dodane" lub "usunięte".

Prowadzenie „liczników” to naprawdę dobra rzecz, a nawet jeśli nie masz z nich natychmiastowego zastosowania, na pewnym etapie cyklu życia aplikacji prawdopodobnie będziesz ich potrzebować. Dlatego bardzo sensowne jest zrozumienie logiki i wdrożenie ich już teraz. Niska cena do zapłacenia teraz, aby później uzyskać wiele korzyści.

Szybka uwaga na marginesie, ponieważ generalnie polecam operacje „luzem” tam, gdzie to możliwe. Używając tego poprzez .collection akcesor w mongoose, musisz mieć świadomość, że są to natywne metody sterowników i dlatego zachowują się inaczej niż metody "mongoose".

Warto zauważyć, że wszystkie metody „mongusty” mają wbudowane „sprawdzenie”, aby sprawdzić, czy połączenie z bazą danych jest aktualnie aktywne. Jeśli tak nie jest, operacja jest skutecznie „kolejkowana” do momentu nawiązania połączenia. Korzystając z metod natywnych, to „sprawdzenie” nie jest już obecne. Dlatego musisz mieć pewność, że połączenie jest już obecne z metody „mongusta”, która wykonała „pierwszy”, lub alternatywnie otoczyć całą logikę aplikacji w konstrukcję, która „czeka” na nawiązanie połączenia:

mongoose.connection.on("open",function(err) {
    // All app logic or start in here
});

W ten sposób masz pewność, że istnieje połączenie, a właściwe obiekty mogą zostać zwrócone i użyte przez metody. Ale brak połączenia, a operacje zbiorcze zakończą się niepowodzeniem.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Używanie MongoDB i Neo4j razem

  2. Projekcja na zapytanie MongoDb przy użyciu danych Spring i QueryDSL

  3. Jak utworzyć niestandardowe zapytanie za pomocą django-nonrel i mongodb

  4. Konwertuj z LinkedHashMap na Json String

  5. Jak wielokrotne wypychanie do zagnieżdżonej tablicy?