Conforme mencionado na primeira parte desta série:Python Database Programming with MongoDB, o módulo Python PyMongo é necessário para que o Python possa se comunicar com um banco de dados MongoDB. Para instalar isso, use o comando no prompt de comando do Windows:
pip3 install pymongo
A instalação do PyMongo deve produzir uma saída semelhante à mostrada abaixo:
Figura 1 – Instalando o módulo PyMongo
Dependendo da configuração do Python, um módulo adicional chamado dnspython também pode ser necessário:
pip3 install dnspython
Figura 2 – Instalando o dnspython módulo
Como inserir dados no MongoDB com Python
O código abaixo criará 15 Artistas gerados aleatoriamente e dois álbuns para cada um deles:
# 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
Uma observação interessante sobre esse código, pelo menos em comparação com os exemplos orientados a SQL em Python Database Programming with SQL Express for Beginners, é que ele é muito mais simples, pois não há componente SQL adicional. As funções JSON já fazem parte do Python e o único comando relacionado ao MongoDB é o insert_many() funções que são executadas após a criação de cada conjunto de dados. Ainda mais conveniente, esses comandos correspondem à mesma sintaxe em Python usada no Shell do MongoDB.
Do ponto de vista da segurança, questões como SQL Injection simplesmente não existem nesse código, não apenas porque não há SQL sendo executado, mas absolutamente nenhum código está sendo passado para o banco de dados. A funcionalidade Lista do Python também cuida de problemas como o escape de aspas.
Em vez de mostrar a saída na janela do prompt de comando, outro pedaço de código será usado para consultar o banco de dados.
Validando as inserções com Python
O código abaixo irá consultar o banco de dados MongoDB para as ações de inserção feitas acima usando 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
A saída abaixo contém os documentos iniciais criados mais adiante no documento:
Figura 3 – Validando as inserções
Consultando dados do MongoDB com Python
O código acima pode ser adaptado em uma ferramenta interativa para consultar os dados com entrada do usuário. O MongoDB fornece uma poderosa ferramenta de pesquisa de texto para suas coleções, mas para habilitá-la, os índices de texto devem ser criados nas coleções a serem pesquisadas:
db.Artists.createIndex({artist_name: "text"}) db.Albums.createIndex({artist_name: "text", album_name: "text"}) Listing 8 - Creating Text Indices for each collection
Observe que o MongoDB permite apenas um índice de texto por coleção. A tentativa de criar outro índice para um nó diferente em uma coleção causará um erro. A saída desses comandos no MongoDB Shell está abaixo:
Figura 4 – Adicionando índices de texto
Embora a ferramenta de pesquisa de texto possa executar todos os tipos de lógica de correspondência maluca envolvendo expressões regulares e correspondências parciais com classificação de proximidade, o exemplo abaixo ficará com correspondência simples, para ilustrar a prova de conceito:
# 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
Observe que nenhuma conversão dos dados provenientes do MongoDB foi necessária para combiná-los com a versão minúscula do termo de pesquisa.
Considerações finais sobre desenvolvimento em Python e MongoDB
Para desenvolvedores que codificam em servidores de banco de dados e bancos de dados orientados a SQL, o salto para o noSQL pode parecer uma curva de aprendizado muito íngreme, mas mapear conceitos familiares de banco de dados SQL para seus equivalentes NoSQL, torna-se um pouco menos desconfortável de subir . Esses desenvolvedores podem até ficar chocados com a falta de “recursos” “básicos”, como aplicação de chave estrangeira ou a expectativa de que é o aplicativo e não o banco de dados que deve impor regras de integridade de dados. Para desenvolvedores de banco de dados orientados a SQL muito experientes, até mesmo o simples pensamento de tais ideias quase parece uma heresia de programação!
Mas bancos de dados NoSQL como o MongoDB adicionam muitos outros recursos que fazem a mudança de pensamento valer a pena. Não precisando se preocupar com mais uma versão do SQL que é “apenas diferente o suficiente” para ser irritante, ou não ter que pensar em questões como injeção de SQL, poder inserir vários registros, err, documentos de dados de forma segura sem o incômodo de “ milhares” de declarações individuais e talvez até divertidas a ideia “louca” de que o aplicativo faça a aplicação de dados reduz uma grande parte dos esforços de desenvolvimento de aplicativos faz com que tudo isso valha a pena.