Wzorce i strategie NoSQL
ENModelowanie danych NoSQL z Claude Code, Codeksem lub Cursorem działa wtedy, gdy agent projektuje na podstawie spisanej listy wzorców dostępu, czyta żywy schemat przez serwer MCP MongoDB lub Neo4j w trybie tylko do odczytu i oddaje mapę wzorców dostępu oraz testy dowodzące, że każde zapytanie korzysta z indeksu. Schemat NoSQL bez tych dowodów to zgadywanie.
Ta strona jest dla programistów, którzy pozwalają agentowi projektować albo zmieniać model danych: dokumentowy, klucz-wartość, grafowy lub wektorowy. Awaria, której zapobiega, wygląda tak: schemat MongoDB był czysty na demie, jeden dokument user z osadzonymi zamówieniami, adresami i koszykiem. Pół roku później tablica zamówień ma 4000 wpisów, dokument zbliża się do limitu 16 MB w MongoDB, a każdy odczyt profilu ciągnie całość przez sieć. Agent, który napisał ten schemat, nigdy nie widział twoich wzorców dostępu, więc zoptymalizował go pod demo.
W NoSQL nie ma schematu relacyjnego, za którym można się schować. Model danych jest projektem, a błędna decyzja „osadzić czy referencjonować” albo zły klucz partycji kosztuje sporo, gdy pojawi się ruch. Poniższe przepisy każą agentowi uzasadnić każdą decyzję, a potem udowodnić ją na prawdziwym silniku. Ty przeglądasz tabelę i raport z testów, a nie każde zapytanie.
Co wyniesiesz z tych przepisów NoSQL
Dział zatytułowany „Co wyniesiesz z tych przepisów NoSQL”- Konfigurację MCP tylko do odczytu dla MongoDB i Neo4j w Claude Code, Codeksie i Cursorze, z flagą, dzięki której MongoDB odrzuca skany kolekcji
- Prompt „osadzić czy referencjonować”, który zmusza agenta do argumentowania wzorcami dostępu i granicami wzrostu
- Prompt do agregacji, w którym plan
explainjest częścią wyniku - Prompt do projektu jednej tabeli DynamoDB, który przypisuje każdemu wzorcowi dostępu warunek klucza albo GSI
- Prompty do Neo4j 5 i Atlas Vector Search, które omijają usuniętą składnię, wciąż generowaną przez agentów
- Zestaw testów wzorców dostępu, pisany przez agenta i uruchamiany w CI, żeby nikt nie musiał czytać każdego zapytania
Jak działa pętla przepisów NoSQL?
Dział zatytułowany „Jak działa pętla przepisów NoSQL?”Każdy magazyn danych przechodzi te same cztery kroki. Zmienia się silnik, pętla zostaje.
- Najpierw spisz wzorce dostępu. Numerowaną listę odczytów i zapisów, których potrzebuje funkcja, z przybliżoną częstotliwością. Ta lista jest specyfikacją i to ją zatwierdzasz.
- Każ agentowi oddać projekt jako artefakt. Tabelę, która każdemu wzorcowi dostępu przypisuje kształt dokumentu, warunek klucza albo indeks, a nie akapit prozy.
- Sprawdź na prawdziwym silniku. Agent czyta prawdziwy schemat i uruchamia
explainprzez MCP albo pracuje na DynamoDB Local, zamiast zgadywać nazwy pól. - Utrwal to testami. Jeden test na wzorzec dostępu sprawdza wynik i plan (użyty indeks, brak skanu). CI uruchamia je przy każdej zmianie.
Krok 1: podłącz agenta do prawdziwego schematu
Dział zatytułowany „Krok 1: podłącz agenta do prawdziwego schematu”Bez połączenia z bazą agent wymyśla nazwy kolekcji i pól. Z połączeniem najpierw pobiera przykładowy dokument, widzi, że już zapisujesz customerId, a nie userId, i trzyma się twojej konwencji. Ogólną konfigurację, role tylko do odczytu i serwery dla innych baz opisuje strona o serwerach MCP dla baz danych; ten krok to część specyficzna dla NoSQL.
Tę stronę obsługują dwa serwery, oba zweryfikowane 2026-09-26:
- MongoDB MCP Server (npm
mongodb-mcp-server3.0.4, oficjalny). Narzędzia to m.in.collection-schema,collection-indexes,find,aggregateiexplain.--readOnlyusuwa narzędzia do tworzenia, aktualizacji i usuwania.--indexCheckodrzuca każde zapytanie, które skanowałoby całą kolekcję, więc „użyj indeksu” przestaje być radą i staje się twardym błędem, który agent musi naprawić. - Neo4j Cypher MCP server (PyPI
mcp-neo4j-cypher0.6.0, zneo4j-contrib). Narzędzia toget_neo4j_schema(wymaga wtyczki APOC),read_neo4j_cypheriwrite_neo4j_cypher;--read-onlyusuwa narzędzie zapisu. To pakiet Pythona, więc uruchamiasz go przezuvx, nienpx.
Serwery działają tak samo we wszystkich trzech narzędziach; różni się tylko miejsce konfiguracji.
Uruchom w terminalu w katalogu głównym repozytorium. -s project zapisuje .mcp.json, a ujęte w apostrofy ${NEO4J_PASSWORD} jest rozwijane z twojej powłoki przy starcie serwera, więc sekret nie trafia do pliku:
claude mcp add -s project mongodb \ -e MDB_MCP_CONNECTION_STRING=mongodb://localhost:27017/shop \ -- npx -y mongodb-mcp-server@3.0.4 --readOnly --indexCheck
claude mcp add -s project neo4j \ -e NEO4J_URI=bolt://localhost:7687 -e NEO4J_USERNAME=neo4j \ -e 'NEO4J_PASSWORD=${NEO4J_PASSWORD}' \ -- uvx mcp-neo4j-cypher@0.6.0 --read-onlyUruchom w terminalu. codex mcp add zapisuje wpis w ~/.codex/config.toml:
codex mcp add mongodb \ --env MDB_MCP_CONNECTION_STRING=mongodb://localhost:27017/shop \ -- npx -y mongodb-mcp-server@3.0.4 --readOnly --indexCheck
codex mcp add neo4j \ --env NEO4J_URI=bolt://localhost:7687 --env NEO4J_USERNAME=neo4j \ --env NEO4J_PASSWORD="$NEO4J_PASSWORD" \ -- uvx mcp-neo4j-cypher@0.6.0 --read-onlyPowstałe wpisy, które możesz też napisać ręcznie:
[mcp_servers.mongodb]command = "npx"args = ["-y", "mongodb-mcp-server@3.0.4", "--readOnly", "--indexCheck"]
[mcp_servers.mongodb.env]MDB_MCP_CONNECTION_STRING = "mongodb://localhost:27017/shop"
[mcp_servers.neo4j]command = "uvx"args = ["mcp-neo4j-cypher@0.6.0", "--read-only"]
[mcp_servers.neo4j.env]NEO4J_URI = "bolt://localhost:7687"NEO4J_USERNAME = "neo4j"NEO4J_PASSWORD = "your-local-password"Powłoka rozwija "$NEO4J_PASSWORD" jeden raz, przy uruchomieniu codex mcp add, więc hasło zostaje zapisane dosłownie w ~/.codex/config.toml. Ten plik należy do użytkownika i leży poza repozytorium; niech tak zostanie. codex mcp get mongodb wypisuje sparsowany wpis z zamaskowanym connection stringiem.
Dodaj do ~/.cursor/mcp.json (poziom użytkownika, poza repozytorium). Wpis Neo4j zawiera hasło zapisane dosłownie, więc nigdy nie umieszczaj go w projektowym .cursor/mcp.json, który trafia do commita. Wpis MongoDB bez danych uwierzytelniających, taki jak lokalny poniżej, może zostać w pliku projektu:
{ "mcpServers": { "mongodb": { "command": "npx", "args": ["-y", "mongodb-mcp-server@3.0.4", "--readOnly", "--indexCheck"], "env": { "MDB_MCP_CONNECTION_STRING": "mongodb://localhost:27017/shop" } }, "neo4j": { "command": "uvx", "args": ["mcp-neo4j-cypher@0.6.0", "--read-only"], "env": { "NEO4J_URI": "bolt://localhost:7687", "NEO4J_USERNAME": "neo4j", "NEO4J_PASSWORD": "your-local-password" } } }}Krok 2: zdecyduj „osadzić czy referencjonować” na podstawie wzorców dostępu
Dział zatytułowany „Krok 2: zdecyduj „osadzić czy referencjonować” na podstawie wzorców dostępu”Najważniejsza decyzja w bazie dokumentowej to, czy powiązane dane osadzić, czy trzymać przez referencję. Agent podejmuje ją dobrze, gdy dostaje wzorce dostępu, wzorzec zapisów i granice wzrostu, a nie prośbę o „dobry schemat”.
Dobra odpowiedź osadza pozycje zamówienia (ograniczone, niezmienne, zawsze czytane razem), zapisuje migawkę customer: { id, name } zamiast robić $lookup przy każdym odczycie i obsługuje wzorzec 2 indeksem złożonym { customerId: 1, createdAt: -1 }. Wzorzec 1 zwraca cały dokument, więc nie może być zapytaniem pokrytym (covered query). Jeśli agent twierdzi inaczej, nie przemyślał projekcji — odeślij mu to do poprawki. Tabela wzorców dostępu to artefakt, który zatwierdzasz. Kod z niej wynika.
Krok 3: każ każdej agregacji udowodnić swój indeks
Dział zatytułowany „Krok 3: każ każdej agregacji udowodnić swój indeks”Potoki agregacji to miejsce, w którym agent oszczędza najwięcej czasu, i zarazem to, gdzie najczęściej oddaje zapytanie zwracające poprawny wynik przy skanie całej kolekcji. Plan wykonania musi być częścią wyniku.
Ponieważ serwer działa z --indexCheck, potok, którego pierwszy $match skanuje kolekcję, kończy się błędem, zamiast zwrócić wiarygodnie wyglądającą odpowiedź. Agent widzi błąd, proponuje indeks, a na lokalnej bazie (gdzie zdjąłeś --readOnly) tworzy go i ponawia explain, aż plan zacznie się od IXSCAN. Liczba, którą czytasz, to stosunek totalDocsExamined do nReturned: bliski 1 jest zdrowy, setki do jednego oznaczają indeks o złym kształcie.
Krok 4: zaprojektuj schemat DynamoDB w jednej tabeli
Dział zatytułowany „Krok 4: zaprojektuj schemat DynamoDB w jednej tabeli”DynamoDB najmocniej karze za mgliste prompty. Klucz partycji o niskiej kardynalności tworzy gorącą partycję, która dławi się pod obciążeniem, a pominięty wzorzec dostępu oznacza Scan na produkcji. Nie ma tu schematu tylko do odczytu, który można by podejrzeć, więc agent pracuje z listy i dowodzi projektu na DynamoDB Local (obraz Dockera amazon/dynamodb-local).
Część wykonywalna jest niewielka. Oto zapytanie dla wzorca 3 w AWS SDK v3 (@aws-sdk/lib-dynamodb 3.1141.0 w npm, 2026-09-26); łańcuch .query(params).promise() z v2 tu nie działa:
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';import { DynamoDBDocumentClient, QueryCommand } from '@aws-sdk/lib-dynamodb';
const ddb = DynamoDBDocumentClient.from(new DynamoDBClient({}));
// GSI1: GSI1PK = USER#<id>, GSI1SK = TASK#<dueDate>#<taskId>export async function getUserTasks(userId, fromDate) { const { Items } = await ddb.send( new QueryCommand({ TableName: 'SaaSPlatform', IndexName: 'GSI1', KeyConditionExpression: 'GSI1PK = :pk AND GSI1SK >= :start', ExpressionAttributeValues: { ':pk': `USER#${userId}`, ':start': `TASK#${fromDate}`, }, ScanIndexForward: true, // ascending by due date }), ); return Items;}Zapisy wsadowe używają BatchWriteCommand, który nadal przyjmuje najwyżej 25 elementów na żądanie.
Krok 5: zamodeluj graf w składni Neo4j 5
Dział zatytułowany „Krok 5: zamodeluj graf w składni Neo4j 5”Przy mocno powiązanych danych (grafy społecznościowe, rekomendacje, siatki oszustów) poproś najpierw o model węzłów i relacji, a dopiero potem o Cypher. Wymagaj składni Neo4j 5: dane treningowe są pełne formy ograniczeń z Neo4j 4, CREATE CONSTRAINT ON ... ASSERT, którą Neo4j 5 odrzuca.
Tak wygląda poprawna odpowiedź:
CREATE CONSTRAINT user_id IF NOT EXISTSFOR (u:User) REQUIRE u.id IS UNIQUE;
CREATE CONSTRAINT post_id IF NOT EXISTSFOR (p:Post) REQUIRE p.id IS UNIQUE;
// Posts friends liked in the last 7 days that this user has not viewedMATCH (user:User {id: $userId})-[:FRIENDS]-(friend:User)-[l:LIKED]->(post:Post)WHERE l.at > datetime() - duration('P7D') AND NOT EXISTS { (user)-[:VIEWED]->(post) }WITH post, count(DISTINCT friend) AS friendLikesRETURN post.id, post.content, friendLikesORDER BY friendLikes DESCLIMIT 10;Ograniczenie user_id daje zapytaniu punkt startowy: EXPLAIN powinien pokazać NodeUniqueIndexSeek na :User(id). AllNodesScan oznacza brak ograniczenia albo literówkę w etykiecie.
Krok 6: dodaj wyszukiwanie wektorowe w MongoDB Atlas
Dział zatytułowany „Krok 6: dodaj wyszukiwanie wektorowe w MongoDB Atlas”Embeddingi zapisane obok dokumentów dają wyszukiwanie semantyczne bez osobnej bazy wektorowej. W MongoDB Atlas odpytujesz je etapem agregacji $vectorSearch na indeksie typu vectorSearch. Starsze mapowanie pola knnVector należy do Atlas Search, jest przestarzałe i nie obsługuje $vectorSearch, a agenci wciąż je generują.
from pymongo.operations import SearchIndexModel
# A vectorSearch index needs SearchIndexModel(type="vectorSearch").# A plain-dict create_search_index() call creates an Atlas Search index instead.db.products.create_search_index( model=SearchIndexModel( definition={ "fields": [ {"type": "vector", "path": "text_embedding", "numDimensions": 384, "similarity": "cosine"}, {"type": "filter", "path": "price"}, {"type": "filter", "path": "categories"}, ] }, name="product_embeddings", type="vectorSearch", ))
pipeline = [ {"$vectorSearch": { "index": "product_embeddings", "path": "text_embedding", "queryVector": query_embedding, # 384 floats from the same model "numCandidates": 200, "limit": 10, "filter": {"price": {"$lte": 100}}, }}, {"$addFields": {"score": {"$meta": "vectorSearchScore"}}}, {"$project": {"text_embedding": 0}},]Jak zweryfikować projekt NoSQL bez czytania każdego zapytania?
Dział zatytułowany „Jak zweryfikować projekt NoSQL bez czytania każdego zapytania?”Zatwierdzasz dwie rzeczy: tabelę wzorców dostępu z kroku projektowego i raport z testów. Nie czytasz każdego potoku, warunku klucza ani zapytania Cypher, bo testy przy każdym przebiegu CI sprawdzają na prawdziwym silniku to, czego szukałby recenzent. To ta sama zmiana, którą opisuje strona o czytaniu dowodów zamiast kodu.
| Magazyn | Co sprawdza test | Kiedy test nie przechodzi |
|---|---|---|
| MongoDB | Każdy wzorzec dostępu zwraca właściwe dokumenty, a wynik explain nie zawiera COLLSCAN | Brakujący albo źle uporządkowany indeks |
| MongoDB | Walidator $jsonSchema odrzuca dokument bez wymaganego pola | Kształt rozminął się z zatwierdzonym projektem |
| DynamoDB | Każdy wzorzec obsługuje Query albo GetItem; middleware rzuca wyjątek przy każdym ScanCommand | Wzorzec dostępu, którego projekt kluczy nie pokrywa |
| Neo4j | EXPLAIN każdego zapytania nie zawiera AllNodesScan; SHOW CONSTRAINTS wymienia każdy klucz unikalny | Usunięte ograniczenie albo literówka w etykiecie |
| Wektory | recall@10 na złotych zapytaniach nie spada poniżej zapisanej wartości bazowej; długość każdego embeddingu równa się numDimensions | Zmiana modelu bez ponownego wygenerowania embeddingów |
Asercja na planie sprawdza cały plan, więc działa zarówno dla planu find, jak i dla planu agregacji:
const plan = await db.collection('orders').aggregate(pipeline).explain('executionStats');expect(JSON.stringify(plan)).not.toContain('COLLSCAN');Uruchamiaj te testy w CI na prawdziwym silniku: kontener MongoDB przez Testcontainers (@testcontainers/mongodb 12.1.0 w npm, 2026-09-26), DynamoDB Local i kontener Neo4j. Zamockowany sterownik nie wygeneruje planu zapytania, więc niczego tu nie dowodzi. Szerszą konfigurację opisują wzorce testowania integracyjnego, a zasilanie bazy realistyczną ilością danych strategie danych testowych.
Kto zatwierdza: programista odpowiedzialny za funkcję akceptuje tabelę wzorców dostępu, zanim powstanie jakikolwiek kod, a CI musi być zielone przed merge’em. Recenzent czyta tabelę, nazwy testów i raport. Jeśli agent zmienia asercję zamiast zapytania, traktuj to jako nieudaną zmianę, tak jak opisuje to strona o ochronie wyroczni testowej.
Kiedy modele danych NoSQL się psują
Dział zatytułowany „Kiedy modele danych NoSQL się psują”- Tablica rośnie bez ograniczeń w stronę limitu 16 MB. Objaw: odczyty profilu z miesiąca na miesiąc zwalniają, potem zapisy kończą się błędem. Naprawa: przenieś tablicę do kolekcji podrzędnej kluczowanej identyfikatorem rodzica (albo podziel ją na kubełki miesięczne), uzupełnij dane migracją i dopisz pytanie o nieograniczony wzrost do promptu projektowego, żeby następny model to uwzględnił.
- Gorąca partycja w DynamoDB. Klucz typu
TENANT#<id>zaczyna być dławiony, gdy ruch jednego najemcy przekroczy limit przepustowości pojedynczej partycji, a dodatkowa przydzielona przepustowość tego limitu nie podnosi. Naprawa: dodaj sufiks sharda (TENANT#<id>#<0-9>), zapisuj do losowego sharda i przy odczycie zbieraj wyniki ze wszystkich (scatter-gather). - Projekcja GSI pomija atrybut. Zapytania do indeksu zwracają elementy bez tego pola, a kod czyta
undefined. Projekcji GSI nie da się zmienić po utworzeniu. Naprawa: utwórz nowy GSI z właściwą projekcją, przełącz odczyty, potem usuń stary. - Superwęzeł w Neo4j. Użytkownik z milionami relacji
FRIENDSzamienia każde przejście grafu od niego w skan. Naprawa: ogranicz rozgałęzienie w zapytaniu (WITH friend LIMIT 1000) albo zamodeluj gorącą relację jako osobny węzeł. - Nieaktualne embeddingi. Wyniki wektorowe po cichu się pogarszają, gdy zmieniasz model embeddingów, a istniejących dokumentów nie przeliczasz. Naprawa: test wymiaru wyłapie zmianę długości; przy zamianie na model o tej samej długości przelicz wszystko i w tej samej zmianie zapisz nową wartość bazową recall.
- Agent wymyśla schemat. Zapytania odwołują się do pól, których nie masz. Naprawa: sprawdź, czy serwer MCP jest podłączony (
/mcpw Claude Code,codex mcp listw Codeksie), i każ agentowi wywołaćcollection-schemaalboget_neo4j_schema, zanim cokolwiek napisze. - Agent próbuje zapisać przez MCP. Z
--readOnlynarzędzia zapisu nie istnieją, więc próba kończy się niegroźnym błędem. Naprawa: zostaw flagę i przeprowadź zmianę migracją; nigdy nie zdejmuj jej, żeby obejść błąd. Szerszy model zagrożeń opisuje strona o zabezpieczaniu serwerów MCP.
Dokąd dalej z modelowaniem danych NoSQL
Dział zatytułowany „Dokąd dalej z modelowaniem danych NoSQL”- Przepisy bazodanowe: hub wszystkich czterech stron z przepisami bazodanowymi
- Serwery MCP dla baz danych: role tylko do odczytu i konfiguracja dla Postgresa, Supabase, Neona i MongoDB
- Wzorce migracji baz danych: jak przeprowadzić indeksy i walidatory z tej strony przez przegląd i CI
- Wzorce optymalizacji SQL: kiedy model relacyjny jest lepszym wyborem
- Najlepsze praktyki ORM: typowany dostęp do danych z Prismą i TypeORM
Czy ten artykuł Ci pomógł?
Jedno kliknięcie, bez logowania.
Co z tym zrobisz?
Jak się czytało?
Co przeszkadzało? Możesz zaznaczyć kilka
Twoja rola?
Dzięki. Czytam każdą odpowiedź. Michał Jaskólski
Pomógł Ci ten artykuł?
Każde to jedno kliknięcie. Zamknij, kiedy chcesz.
bez logowania