Jak wspomniano w pierwszej części tej serii:Python Database Programming with MongoDB, moduł Pythona PyMongo jest wymagane, aby Python mógł komunikować się z bazą danych MongoDB. Aby to zainstalować, użyj polecenia w wierszu poleceń systemu Windows:
pip3 install pymongo
Instalacja PyMongo powinna dać wynik podobny do tego, który pokazano poniżej:
Rysunek 1 – Instalacja modułu PyMongo
W zależności od konfiguracji Pythona dodatkowy moduł o nazwie dnspython może być również konieczne:
pip3 install dnspython
Rysunek 2 – Instalacja dnspythona moduł
Jak wstawiać dane do MongoDB za pomocą Pythona
Poniższy kod utworzy 15 losowo wygenerowanych artystów i dwa Albumy dla każdego z nich:
# bad-band-name-maker-nosql.py import sys import random import pymongo part1 = ["The", "Uncooked", "Appealing", "Larger than Life", "Drooping", "Unwell", "Atrocious", "Glossy", "Barrage", "Unlawful"] part2 = ["Defeated", "Hi-Fi", "Extraterrestrial", "Adumbration", "Limpid", "Looptid", "Cromulent", "Unsettled", "Soot", "Twinkle"] part3 = ["Brain", "Segment", "\"Audio\"", "Legitimate Business", "\"Bob\"", "Sound", "Canticle", "Monsoon", "Preserves", "\"Cacophony\""] part4 = ["Cougar", "Lion", "Lynx", "Ocelot", "Puma", "Jaguar", "Panther"] part5 = ["Fodder", "Ersatz Goods", "Leftovers", "Infant Formula", "Mush", "Smoothie", "Milkshakes"] def main(argv): # Connect to the RazorDemo database. client = pymongo.MongoClient("mongodb+srv://yourUser:[email protected]/RazorDemo?retryWrites=true&w=majority", serverSelectionTimeoutMS=5000) artistsCollection = client["RazorDemo"]["Artists"] albumsCollection = client["RazorDemo"]["Albums"] # Generate 15 bad band names, and try to keep them unique. previousNames = "" nameCount = 0 artistJson = [] while (nameCount < 16): rand1 = random.randrange(0, 9) rand2 = random.randrange(0, 9) rand3 = random.randrange(0, 9) badName = part1[rand1] + ' ' + part2[rand2] + ' ' + part3[rand3] # Unlike with SQL-oriented databases, MongoDB allows for the insertion of multiple documents in a single statement. # In this case, the code will build a JSON list of all the band names to be inserted in a one fell swoop. if ("|" + previousNames + "|").find("|" + badName + "|") == -1: #print ("Band name [" + str(nameCount) + "] is [" + badName + "]") # Don't forget to escape quotation marks! jsonEntry = { "artist_name" : badName } artistJson.append(jsonEntry) # Because there are no foreign key rules, the album names can be created # and committed to the database before the artist names have been created. albumJson = [] for y in range(1, 3): rand4 = random.randrange(0, len(part4)) rand5 = random.randrange(0, len(part5)) # No checks for uniqueness here. Peter Gabriel had 4 self-titled # albums after all. albumName = part4[rand4] + " " + part5[rand5] albumEntry = { "artist_name" : badName, "album_name" : albumName } albumJson.append(albumEntry) print (albumJson) albumsCollection.insert_many(albumJson) # Creates a bar-delimited list of previously used names. # MongoDB expects the application to enforce data integrity rules. if previousNames == "": previousNames = badName else: previousNames = previousNames + "|" + badName nameCount = 1 + nameCount else: print ("Found a duplicate of [" + badName + "]") print (artistJson) artistsCollection.insert_many(artistJson) # Close the Connection client.close() return 0 if __name__ == "__main__": main(sys.argv[1:]) Listing 6 - Creating Random Data
Interesującą obserwacją dotyczącą tego kodu, przynajmniej w porównaniu z przykładami zorientowanymi na SQL w Python Database Programming with SQL Express for Beginners, jest to, że jest on znacznie prostszy, ponieważ nie ma dodatkowego komponentu SQL. Funkcje JSON są już częścią Pythona, a jedynym poleceniem związanym z MongoDB jest insert_many() funkcje, które są wykonywane po utworzeniu każdego zestawu danych. Jeszcze wygodniej, te polecenia pasują do tej samej składni w Pythonie, która jest używana w powłoce MongoDB.
Z punktu widzenia bezpieczeństwa, problemy takie jak SQL Injection po prostu nie istnieją w takim kodzie, nie tylko dlatego, że SQL nie jest wykonywany, ale absolutnie żaden kod nie jest przesyłany do bazy danych. Funkcjonalność Python List rozwiązuje również problemy, takie jak unikanie znaków cudzysłowu.
Zamiast pokazywać dane wyjściowe w oknie wiersza poleceń, inny fragment kodu zostanie użyty do zapytania bazy danych.
Weryfikowanie wstawek za pomocą Pythona
Poniższy kod wyśle zapytanie do bazy danych MongoDB o działania wstawiania wykonane powyżej przy użyciu Pythona:
# bad-band-name-display-nosql.py import sys import pymongo def main(argv): # Connect to the RazorDemo database. client = pymongo.MongoClient("mongodb+srv://yourUser:[email protected]/RazorDemo?retryWrites=true&w=majority", serverSelectionTimeoutMS=5000) artistsCollection = client["RazorDemo"]["Artists"] albumsCollection = client["RazorDemo"]["Albums"] print ("Albums:") artists = artistsCollection.find() for artist in artists: print (str(artist["artist_name"])) albumQuery = { "artist_name": {"$eq" : str(artist["artist_name"])} } albumsForThisArtist = albumsCollection.find(albumQuery) for album in albumsForThisArtist: print ("\t" + str(album["album_name"])) # Close the Connection client.close() return 0 if __name__ == "__main__": main(sys.argv[1:]) Listing 7 - Validating the Insert Actions
Poniższe dane wyjściowe zawierają początkowe dokumenty utworzone w dalszej części dokumentu:
Rysunek 3 – Weryfikacja wstawek
Odpytywanie danych MongoDB za pomocą Pythona
Powyższy kod można zaadaptować do interaktywnego narzędzia do sprawdzania danych za pomocą danych wejściowych użytkownika. MongoDB zapewnia potężne narzędzie do wyszukiwania tekstu w swoich kolekcjach, ale aby to umożliwić, należy utworzyć indeksy tekstowe w kolekcjach, które mają być przeszukiwane:
db.Artists.createIndex({artist_name: "text"}) db.Albums.createIndex({artist_name: "text", album_name: "text"}) Listing 8 - Creating Text Indices for each collection
Zwróć uwagę, że MongoDB dopuszcza tylko jeden indeks tekstowy na kolekcję. Próba utworzenia innego indeksu dla innego węzła w kolekcji spowoduje błąd. Dane wyjściowe tych poleceń w MongoDB Shell są poniżej:
Rysunek 4 – Dodawanie indeksów tekstowych
Podczas gdy narzędzie do wyszukiwania tekstu może wykonywać wszelkiego rodzaju szaloną logikę dopasowywania obejmującą wyrażenia regularne i częściowe dopasowania z rankingiem bliskości, poniższy przykład będzie trzymał się prostego dopasowywania, aby zilustrować weryfikację koncepcji:
# bad-band-name-query-nosql.py import sys import pymongo def main(argv): searchValue = input("Enter something: ") # Cap the length at something reasonable. The first 20 characters. searchValue = searchValue[0:20] # Set the search value to lower case so we can perform case-insensitive matching: searchValue = searchValue.lower() # Connect to the RazorDemo database. client = pymongo.MongoClient("mongodb+srv://yourUser:[email protected]/RazorDemo?retryWrites=true&w=majority", serverSelectionTimeoutMS=5000) artistsCollection = client["RazorDemo"]["Artists"] albumsCollection = client["RazorDemo"]["Albums"] matchedArtists = ""; artists = artistsCollection.find( { "$text":{ "$search": searchValue} }) for artist in artists: matchedArtists = matchedArtists + "\t" + str(artist["artist_name"]) + "\r\n" if "" == matchedArtists: print ("No matched artists.") else: print ("Matched Artists:") print (matchedArtists) albums = albumsCollection.find( { "$text":{ "$search": searchValue} }) matchedAlbums = "" for album in albums: matchedAlbums = matchedAlbums + "\t" + str(album["artist_name"]) + " - " + str(album["album_name"]) + "\r\n" if "" == matchedAlbums: print ("No matched albums.") else: print ("Matched Albums:") print (matchedAlbums) # Close the Connection client.close() return 0 if __name__ == "__main__": main(sys.argv[1:]) Listing 9 - Querying the data
Pamiętaj, że nie była potrzebna żadna konwersja danych wychodzących z MongoDB, aby dopasować je do wersji wyszukiwanego hasła pisanej małymi literami.
Końcowe przemyślenia na temat rozwoju Pythona i MongoDB
Dla programistów, którzy programowali na serwerach baz danych i bazach danych zorientowanych na SQL, przejście na noSQL może wydawać się skalowaniem bardzo stromej krzywej uczenia się, ale mapowanie znanych koncepcji baz danych SQL na ich odpowiedniki w NoSQL sprawia, że wspinaczka staje się nieco mniej niewygodna. . Tacy programiści mogą być nawet zszokowani brakiem „podstawowych” „funkcji”, takich jak wymuszanie klucza obcego lub oczekiwanie, że to aplikacja, a nie baza danych, ma egzekwować reguły integralności danych. Dla bardzo doświadczonych programistów baz danych zorientowanych na SQL, nawet sama myśl o takich pomysłach prawie wydaje się programową herezją!
Ale bazy danych NoSQL, takie jak MongoDB, dodają wiele innych funkcji, dzięki którym warto zmienić sposób myślenia. Nie trzeba się martwić o kolejną wersję SQL, która jest „wystarczająco inna”, aby była denerwująca, lub nie trzeba myśleć o problemach, takich jak wstrzykiwanie SQL, możliwość bezpiecznego wstawiania wielu rekordów, błędów, dokumentów danych bez kłopotów z „ tysiące” indywidualnych wypowiedzi, a może nawet zabawnych „szalony” pomysł, że posiadanie aplikacji do egzekwowania danych zmniejsza ogromną część wysiłków związanych z tworzeniem aplikacji, sprawia, że wszystko to jest warte rozważenia.