How to insert data inside Mongo object through Python - python

Inside the expenses collection I have this Json:
{
"_id" : ObjectId("5ad0870d2602ff20497b71b8"),
"Hotel" : {}
}
I want to insert a document or another object if possible inside Hotel using Python.
My Python code:
from pymongo import MongoClient
client = MongoClient('localhost', 27017)
db = client['db']
collection_expenses = db ['expenses']
#insert
d = int(input('Insert how many days did you stay?: '))
founded_expenses = collection_expenses.insert_one({'days':d})
The code above inserts the document inside the collection. What should I change to add the days inside de Hotel object?
Thanks in advance.

Instead of using insert_one, you may want to take a look to the save method, which is a little bit more permissive.
Admitting your document is already created in the collection:
[...]
expenses = db['expenses']
# Find your document
expense = expense.find_one({})
expense["Hotel"] = { "days": d }
# This will either update or save as a new document the expense dict,
# depending on whether or not it already has an _id parameter
expenses.save(expense)
Knowing that find_one will return you None if no such document exist, you may want to upsert a document. You can thus easily do so with save.

Related

Iterate over json on sqlalchemy query

I'm working with on a project that has a questionnaire in it.
I'm using Python, Flask, Postgres and Sqlalchemy.
I need to build a search endpoint that filters the documents by the title or by any of the answers in the questionnaire.
The database is structured the following way:
[Client] - One to Many - [Document] - One to Many - [DocumentVersion]
So that one Client can have many Documents and each document may have many Document Versions.
### DocumentVersion Model
class DocumentVersion(db.Model):
__tablename__ = 'document_version'
id = db.Column(db.Integer, primary_key=True)
document_id = db.Column(db.Integer, db.ForeignKey('document.id'), nullable=False)
answers = db.Column(JSON, nullable=False)
# ... other columns
document = relationship('Document', back_populates='versions')
#hybrid_method
def answers_contain(self, text):
'''returns True if the text appears in any of the answers'''
contains_text = False
for answer in self.answers:
if text == str(answer['answer'].astext):
contains_text = True
return contains_text
Inside the [DocumentVersion] table, there is a JSONB field storing the questions and the answers.
The json is structured the following way:
[{
"value": "question"
"answer": "foo",
...
},
{
"value": "question"
"answer": "bar",
...
},
...
]
The filter document by document title is working fine, but I can't figure out a way to filter by the answers in the json.
I believe I have to iterate over the json to make the filter. So I tried to create a #hybrid_method called answers_contain to do so,
but when I do for answer in self.answers in the hydrid method, the loop actually never ends. I wonder if it's possible to iterate over the json
while making the query. If I try len(self.answers) inside the hybrid method, I get a
TypeError: object of type 'InstrumentedAttribute' has no len().
### Search endpoint
try:
page = int(request.args.get('page', 1))
per_page = int(request.args.get('per_page', 20))
search_param = str(request.args.get('search', ''))
except:
abort(400, "invalid parameters")
paginated_query = Document.query \
.filter_by(client_id=current_user['client_id']) \
.join(Document.versions) \
.filter(or_(
Document.title.ilike(f'%{search_param}%'),
DocumentVersion.answers_contain(f'%{search_param}%'),
)) \
.order_by(desc(Document.created_at)) \
.paginate(page=page, per_page=per_page)
I also tried to filter like this:
DocumentVersion.answers.ilike(f'%{search_param}%'), which gives me an error and a hint:
HINT: No operator matches the given name and argument types. You might need to add explicit type casts. If I added explicit type casts I would have to hardcode the questions, but I can't, since they can change.
What is the best way to do this filtering? I'd like to avoid bringing all the client documents to the backend server, if possible.
Is there a way to iterate over the json while making the query, on the db server?
Thanks in advance.

How do I retrieve a path's data from firebase database using python?

I have this firebase database structure
I want to print out the inventory list(Inventory) for each ID under Businesses.
So I tried this code
db = firebase.database()
all_users = db.child("Businesses").get()
for user in all_users.each():
userid = user.key()
inventorydb = db.child("Businesses").child(userid).child("Inventory")
print(inventorydb)
but all I got is this
<pyrebase.pyrebase.Database object at 0x1091eada0>
what am I doing wrong and how can I loop through each Business ID and print out their inventory?
First, you're printing a Database object. You need to get the data still.
You seem to already know how to get that as well as the children. Or you only copied the examples without understanding it...
Either way, you can try this
db = firebase.database()
businesses = db.child("Businesses")
for userid in businesses.shallow().get().each():
inventory = businesses.child(userid).child("Inventory").get()
print( inventory.val() )
On a side note, National_Stock_Numbers looks like it should be a value of the name, not a key for a child

Storing JSON into database in python

I'm fetching some data from an API on regular interval and wants to store the JSON data into database to access and use later.
From API, I get data in this sample each time:
'{"data": {"cursor": null, "files": {"nodes": [{u'code': u'BOPhmYQg5Vm', u'date': 1482244678,u'counts': 2, u'id': u'1409492981312099686'}, {u'code': u'g5VmBOPhmYQ', u'date': 1482244678,u'counts': 5, u'id': u'1209968614094929813'}]}}}'
I can json_data = json.loads(above_data) and then fetch nodes as nodes_data = json_data["data"]["files"]["nodes"] which gives a list of nodes.
I want to store this nodes data into DB column data = Column(db.Text) of Text type. Each time there are going to be 10-15 values in nodes list.
How do I store? There are multiple nodes and I need it in a way that in future I can append/add more nodes to already available data column in my db.
While I would like to do json.loads(db_data_col) so that I get valid json and can loop over all of nodes to get internal data and use later.
I'm confused on how to store in db and access later in valid json format.
Edit 1: Using Sqlite for testing. Can use PostgresSQL in future. Text type of column is main point.
If you are using Django 1.8 you can create your own model field that can store a json. This class will make sure that you have the right JSON format as well.
import json
from django.db import models
class JsonField(models.TextField):
"""
Stores json-able python objects as json.
"""
def get_db_prep_value(self, value, connection, prepared=False):
try:
return json.dumps(value)
except TypeError:
BAD_DATA.error(
"cannot serialize %s to store in a JsonField", str(value)
)
return ""
def from_db_value(self, value, expression, connection, context):
if value == "":
return None
try:
return json.loads(value)
except TypeError:
BAD_DATA.error("cannot load dictionary field -- type error")
return None
I found a way to store JSON data into DB. Since I'm accessing nodes from remote service which returns a list of nodes on every request, I need to build proper json to store/retrieve from db.
Say API returned json text as : '{"cursor": null, "nodes" = [{"name": "Test1", "value: 1}, {"name": "Test2", "value: 2}, ...]}'
So, first we need to access nodes list as:
data = json.loads(api_data)
nodes = data['nodes']
Now for 1st entry into DB column we need to do following:
str_data = json.dumps({"nodes": nodes})
So, str_data would return a valid string/buffer, which we can store into DB with a "nodes" key.
For 2nd or successive entries into DB column, we will do following:
# get data string from DB column and load into json
db_data = json.loads(db_col_data)
# get new/latest 'nodes' data from api as explained above
# append this data to 'db_data' json as
latest_data = db_data["nodes"] + new_api_nodes
# now add this data back to column after json.dumps()
db_col_data = json.dumps(latest_data)
# add to DB col and DB commit
It is a proper way to load/dump data from DB while adding/removing json and keeping proper format.
Thanks!

Switch collection in mongoengine for find query

I've read mongoengine documentation about switching collection to save document. And test this code and it worked successfully:
from mongoengine.context_managers import switch_db
class Group(Document):
name = StringField()
Group(name="test").save() # Saves in the default db
with switch_collection(Group, 'group2000') as Group:
Group(name="hello Group 2000 collection!").save() # Saves in group2000 collection
But the problem is when I want to find saved document in switch collection switch_collection doesn't work at all.
with switch_collection(Group, 'group2000') as GroupT:
GroupT.objects.get(name="hello Group 2000 collection!") # Finds in group2000 collection
As of mongoengine==0.10.0 mongoengine.context_managers.switch_collection(cls, collection_name)
used as "with switch_collection(Group, 'group1') as Group:" in the example
doesn't work inside functions. It gives unboundlocalerror. A simple get around with existing resources is :
To get:
new_group = Group.switch_collection(Group(),'group1')
from mongoengine.queryset import QuerySet
new_objects = QuerySet(Group,new_group._get_collection())
Use new_objects.all() to get all objects etc.
To save:
group_obj = Group()
group_obj.switch_collection('group2')
group_obj.save()
Although Prachetos Sadhukhan answer works for me, I prefer to get the collection directly, not relying on private _get_collection method:
from mongoengine import connection
new_group_collection = connection.get_db()['group1']
from mongoengine.queryset import QuerySet
new_objects = QuerySet(Group, new_group_collection)

Python, CouchDb: how to Update already existing document by ID

I am trying to update an already existing document by ID. My intention is to find the doc by its id, then change its "firstName" with new value coming in "json", then update it into the CouchDB database.
Here is my code:
def updateDoc(self, id, json):
doc = self.db.get(id)
doc["firstName"] = json["firstName"]
doc_id, doc_rev = self.db.save(doc)
print doc_id, doc_rev
print "Saved"
//"json" is retrieved from PUT request (request.json)
at self.db.save(doc) I'm getting exception as "too many values to unpack".
I am using Bottle framework, Python 2.7 and Couch Query.
How do I update the document by id? what is the right way to do it?
In couchdb-python the db.save(doc) method returns tuple of _id and _rev. You're using couch-query - a bit different project that also has a db.save(doc) method, but it returns a different result. So your code should look like this:
def updateDoc(self, id, json):
doc = self.db.get(id)
doc["firstName"] = json["firstName"]
doc = self.db.save(doc)
print doc['_id'], doc['_rev']
print "Saved"

Categories