Zoals vermeld in het eerste deel van deze serie:Python Database Programming met MongoDB, de Python-module PyMongo is vereist voor Python om te kunnen communiceren met een MongoDB-database. Om dit te installeren, gebruik je het commando op de Windows Command Prompt:
pip3 install pymongo
Het installeren van PyMongo zou een uitvoer moeten opleveren die vergelijkbaar is met wat hieronder wordt weergegeven:
Figuur 1 – De PyMongo-module installeren
Afhankelijk van de Python-configuratie, een extra module genaamd dnspython kan ook nodig zijn:
pip3 install dnspython
Figuur 2 – Installatie van de dnspython module
Hoe gegevens in MongoDB in te voegen met Python
De onderstaande code creëert 15 willekeurig gegenereerde Artiesten en twee Albums voor elk van hen:
# 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
Een interessante observatie over deze code, in ieder geval vergeleken met de SQL-georiënteerde voorbeelden in Python Database Programming with SQL Express for Beginners, is dat het veel eenvoudiger is, omdat er geen extra SQL-component is. De JSON-functies maken al deel uit van Python en de enige MongoDB-gerelateerde opdracht is de insert_many() functies die worden uitgevoerd nadat elke dataset is gemaakt. Nog handiger, deze commando's komen overeen met dezelfde syntaxis in Python die wordt gebruikt in de MongoDB Shell.
Vanuit veiligheidsoogpunt bestaan problemen zoals SQL-injectie gewoon niet in dergelijke code, niet alleen omdat er geen SQL wordt uitgevoerd, maar er wordt absoluut geen enkele code aan de database doorgegeven. De Python List-functionaliteit zorgt ook voor problemen zoals het ontsnappen van aanhalingstekens.
In plaats van de uitvoer in het opdrachtpromptvenster te tonen, wordt in plaats daarvan een ander stuk code gebruikt om de database te doorzoeken.
De invoegingen valideren met Python
De onderstaande code zal de MongoDB-database opvragen voor de invoegacties die hierboven zijn gemaakt met Python:
# 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
De uitvoer hieronder bevat de oorspronkelijke documenten die verderop in het document zijn gemaakt:
Figuur 3 – Validatie van de bijlagen
MongoDB-gegevens opvragen met Python
De bovenstaande code kan worden aangepast tot een interactief hulpmiddel om de gegevens op te vragen met gebruikersinvoer. MongoDB biedt een krachtige tekstzoekfunctie voor zijn collecties, maar om dit mogelijk te maken, moeten er tekstindexen worden gemaakt op de collecties die moeten worden doorzocht:
db.Artists.createIndex({artist_name: "text"}) db.Albums.createIndex({artist_name: "text", album_name: "text"}) Listing 8 - Creating Text Indices for each collection
Merk op dat MongoDB slechts één tekstindex per verzameling toestaat. Als u probeert een andere index te maken voor een ander knooppunt in een verzameling, treedt er een fout op. De uitvoer van deze opdrachten in MongoDB Shell is hieronder:
Figuur 4 – Tekstindexen toevoegen
Hoewel de tekstzoekfunctie allerlei gekke matching-logica kan uitvoeren met reguliere expressies en gedeeltelijke overeenkomsten met rangorde van nabijheid, blijft het onderstaande voorbeeld bij eenvoudige overeenkomsten, om het proof-of-concept te illustreren:
# 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
Houd er rekening mee dat er geen conversie van de gegevens die uit MongoDB komen nodig was om deze te matchen met de kleine versie van de zoekterm.
Definitieve gedachten over de ontwikkeling van Python en MongoDB
Voor ontwikkelaars die hebben gecodeerd tegen SQL-georiënteerde databaseservers en databases, kan de sprong naar noSQL aanvoelen als een zeer steile leercurve, maar door bekende SQL-databaseconcepten toe te wijzen aan hun NoSQL-tegenhangers, wordt het een beetje minder ongemakkelijk van een klim . Dergelijke ontwikkelaars kunnen zelfs geschokt zijn door het ontbreken van "basis" "functies" zoals het afdwingen van externe sleutels of de verwachting dat het de applicatie is en niet de database die naar verwachting de regels voor gegevensintegriteit zal handhaven. Voor zeer doorgewinterde SQL-georiënteerde databaseontwikkelaars voelt zelfs de gedachte alleen al aan dergelijke ideeën bijna als ketterij programmeren!
Maar NoSQL-databases zoals MongoDB voegen veel andere functies toe die de verandering in denken de moeite waard maken. Geen zorgen hoeven te maken over weer een andere versie van SQL die "net anders genoeg" is om vervelend te zijn, of niet hoeven na te denken over zaken als SQL-injectie, meerdere records kunnen invoegen, err, documenten met gegevens veilig zonder het gedoe van " duizenden” individuele uitspraken, en misschien zelfs vermakelijk het "gekke" idee dat het hebben van de applicatie de gegevenshandhaving een groot deel van de inspanningen voor applicatie-ontwikkeling afschaaft, maakt het allemaal de overweging waard.