'DocumentReference' object has no attribute 'to_dict' - python-3.x

I'm using python3 to query a database on firestore. My code is the following:
def getWebConsultReData():
collection = db.collection("webconsult_threescrap").where("compositeKey", "==", "10004-5327729026")
docs = [snapshot.reference for snapshot in collection.stream()]
mDictList = []
print(docs)
for doc in docs:
formattedData = doc.to_dict()
getWebConsultReData()
However, I got the following error:
[<google.cloud.firestore_v1.document.DocumentReference object at 0x7f2a183413c8>]
Traceback (most recent call last):
File "<ipython-input-42-172d5765da1d>", line 9, in <module>
getWebConsultReData()
File "<ipython-input-42-172d5765da1d>", line 7, in getWebConsultReData
formattedData = doc.to_dict()
AttributeError: 'DocumentReference' object has no attribute 'to_dict'
What I'm sure are:
The filter is valid, in fact, the following snapshot shows the exact syntax with GUI
Also the document exists.
Can anybody help me out? Thank you very much!

Your problem is that at the point of the error, docs is an array of DocumentReferences and not an array of DocumentSnapshots because you remove all the other data a few lines up. DocumentReference only gives a path to the document, it does not contain the entirety of the document's data.
To do something equivalent (gather an array of DocumentReferences but also have some access to the actual documents), you'd need to do something like this:
def getWebConsultReData():
collection = db.collection("webconsult_threescrap").where("compositeKey", "==", "10004-5327729026")
docs = []
for doc in collection.stream():
formattedData = doc.to_dict()
print(formattedData)
docs.append(doc.reference)
print(docs)
getWebConsultReData()
If it helps, you can also review the example in the documentation of how to get multiple documents from a collection.

from google.cloud import firestore
def tableconversations(userdata):
docarray = []
db = firestore.Client()
collection = db.collection('tableQuestions').where('userID', '==', userdata['ID']).get()
print("user history matched records",collection)
for doc in collection:
print(doc.to_dict())
docarray.append(doc.to_dict())
return docarray

Related

Flask + Firestore adding all doc elements to a dictionary {not looping}

I must be doing something wrong
I'm trying to loop through all documents in a collection and add the contents to a dictionary.
I added the data to a dictionary, but my intention was to loop through all docs:
firebase_admin.initialize_app(cred)
db = firestore.client()
blog_col = db.collection(u'blog')
class Art_cont:
def __init__(self,title,date,link):
self.title = title
self.date = date
self.link = link
def getLast4():
query = blog_col.order_by("date").limit_to_last(4).get()
for doc in query: #Need to find a way to loop through all docs, this doesn't work
db_title=doc.to_dict()["title"]
db_date=doc.to_dict()["date"]
db_link=doc.to_dict()["link"]
content1=Art_cont(db_title,db_date,db_link)
#here wrap them up with html and return them to app
print(content1.title,content1.date,content1.link)
When I run that code it only gives me the first doc content:
Vs the other docs that have the same structure:
Any advice would be appreciated.
Assuming that query is an object of your model, write db_title = doc.your_attribute_name.to_dict()['title'] and do the same for the other attributes.
Well, I almost had it, I ended up creating a function instead:
def getlist(x):
query = blog_col.order_by("date").limit_to_last(4).get()
docs=[]
for doc in query:
docs.append(doc)
docnum=docs[x]
db_title=docnum.to_dict()["title"]
db_date=docnum.to_dict()["date"]
db_link=docnum.to_dict()["link"]
content=Art_cont(db_title,db_date,db_link)
return content
print(getlist(0).title)
print(getlist(1).title)
etc...
Hope this helps anyone in a similar situation.

Check if the collection query returned a set of documents - Firestore python

According to documentation here to query a set of documents we need to use the collection query.
Once we execute the query. And use the following code to find if there are documents.
code_ref = db.collection(u'col1')
code_query = code_ref.limit(1)
code_docs = code_query.get()
code_docs_array = []
for elements in code_docs:
code_docs_array.append(elements)
if (len(code_docs_array) > 0):
# there are docs
else:
# there are no docs
I am sure the above method is inefficient. Is there a equivalent to docs.exists function when dealing with collection query?
You should be able to check 'exists' within each object returned from the query.
Here is a test I just ran:
db = firestore.client()
query = db.collection(u'projects').where(u'name', u'==', 'myname').limit(1).get()
for doc in query:
if doc.exists:
print("Document found")

pymodm can't find an object, while pymongo successfully finds it

I have a problem getting an object from the mongodb instance. If I search for this object with pymongo interface, everything is fine - object can be found. If try to do the very same thing with pymodm - it fails with error.
Here is what I'm doing:
from pymodm import connect, MongoModel, fields
from pymongo import MongoClient
class detection_object(MongoModel):
legacy_id = fields.IntegerField()
client = MongoClient(MONGODB_URI)
db = client[MONGODB_DEFAULT_SCHEME]
collection = db['detection_object']
do = collection.find_one({'legacy_id': 1437424})
print(do)
connect(MONGODB_URI)
do = detection_object.objects.raw({'legacy_id': 1437424}).first()
print(do)
The first print outputs this: {'_id': ObjectId('5c4099dcffa4fb11494d983d'), 'legacy_id': 1437424}. However, during the execution of this command: do = detection_object.objects.raw({'legacy_id': 1437424}).first() interpreter fails with the following error:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/pymodm/queryset.py", line 127, in first
return next(iter(self.limit(-1)))
StopIteration
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/konsof01/PycharmProjects/testthisfuckingshit/settings.py", line 29, in <module>
do = detection_object.objects.raw({'legacy_id': 1437424}).first()
File "/usr/local/lib/python3.7/site-packages/pymodm/queryset.py", line 129, in first
raise self._model.DoesNotExist()
__main__.DoesNotExist
How can this be? I'm trying to query the very same object, with the same connection and collection. Any ideas, please?
you could try it as follows:
detection_object.objects.raw({'legacy_id': "1437424"} ).first()
probably the legacy_id is stored as string.
Othewise, make sure the db name is present at the end of the MONGO_URI as it is underlined in the docs.
Each document in your 'detection_object' collection requires to have '_cls' attribute. The string value stored in this attribute should be
__main__.classname
(class name according to your code is detection_object).
For example a document in your database needs to look like this:
{'_id': ObjectId('5c4099dcffa4fb11494d983d'), 'legacy_id': 1437424, '_cls': '__ main __.detection_object'}

Method createIndex() not callable on a collection

In the doc of the createIndex they say db.collection.createIndex(keys, options) so i call createIndex() with the code below. The name of my database is articles and the name of the collection is bce. Inside bce there is already a document with the field article.
class Stockage():
def __init__(self):
self.connexion()
def connexion(self):
client = pymongo.MongoClient("localhost", 27017)
self.bce = client.articles.bce
sql = Stockage()
sql.bce.createIndex({article : "text"})
And i have the following error :
Traceback (most recent call last):
File "<ipython-input-1132-fc8762d315d1>", line 1, in <module>
sql.bce.createIndex({article : "text"})
File "C:\ProgramData\Anaconda3\lib\site-packages\pymongo\collection.py", line 3321, in __call__
self.__name.split(".")[-1])
TypeError: 'Collection' object is not callable. If you meant to call the 'createIndex' method on a 'Collection' object it is failing because no such method exists.
Is not bce a collection ?
This is because in Pymongo the method is called create_index() instead of createIndex() as it is named in the mongo shell.
It also has a different format for the parameter compared to its mongo shell counterpart. Instead of accepting a document/dict as index specification, it accepts a list of tuples instead. This is because you cannot guarantee the ordering of dict keys in Python.
So the correct line should be:
sql.bce.create_index([("article", pymongo.TEXT)])
More details are available in the Pymongo Collection page.

Revit API & Dynamo, Creating a Family Parameter from Project Document

I'm trying to create a new family parameter by calling a family's document in a project document and using the FamilyManager method to edit the family. There have been about 10 people asking for this on the Dynamo forums, so I figured I'd give it a shot. Here's my Python script below:
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference("RevitServices")
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *
#The inputs to this node will be stored as a list in the IN variables.
familyInput = UnwrapElement(IN[0])
familySymbol = familyInput.Symbol.Family
doc = familySymbol.Document
par_name = IN[1]
par_type = ParameterType.Text
par_grp = BuiltInParameterGroup.PG_DATA
TransactionManager.Instance.EnsureInTransaction(doc)
familyDoc = doc.EditFamily(familySymbol)
OUT = familyDoc.FamilyManager.AddParameter(par_name,par_grp,par_type,False)
TransactionManager.Instance.TransactionTaskDone()
When I run the script, I get this error:
Warning: IronPythonEvaluator.EvaluateIronPythonScript operation failed.
Traceback (most recent call last):
File "<string>", line 26, in <module>
Exception: The document is currently modifiable! Close the transaction before calling EditFamily.
I'm assuming that this error is because I am opening a family document that already exists through the script and then never sending the information back to the project document? Or something similar to that. Any tips on how to get around this?
Building up on our discussion from the forum:
import clr
clr.AddReference("RevitServices")
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *
par_name = IN[0]
exec("par_type = ParameterType.%s" % IN[1])
exec("par_grp = BuiltInParameterGroup.%s" % IN[2])
inst_or_typ = IN[3]
families = UnwrapElement(IN[4])
# class for overwriting loaded families in the project
class FamOpt1(IFamilyLoadOptions):
def __init__(self): pass
def OnFamilyFound(self,familyInUse, overwriteParameterValues): return True
def OnSharedFamilyFound(self,familyInUse, source, overwriteParameterValues): return True
trans1 = TransactionManager.Instance
trans1.ForceCloseTransaction() #just to make sure everything is closed down
# Dynamo's transaction handling is pretty poor for
# multiple documents, so we'll need to force close
# every single transaction we open
result = []
for f1 in families:
famdoc = doc.EditFamily(f1)
try: # this might fail if the parameter exists or for some other reason
trans1.EnsureInTransaction(famdoc)
famdoc.FamilyManager.AddParameter(par_name, par_grp, par_type, inst_or_typ)
trans1.ForceCloseTransaction()
famdoc.LoadFamily(doc, FamOpt1())
result.append(True)
except: #you might want to import traceback for a more detailed error report
result.append(False)
trans1.ForceCloseTransaction()
famdoc.Close(False)
OUT = result
image of the Dynamo graph
The error message is already telling you exactly what the problem is: "The document is currently modifiable! Close the transaction before calling EditFamily".
I assume that TransactionManager.Instance.EnsureInTransaction opens a transaction on the given document. You cannot call EditFamily with an open transaction.
That is clearly documented in the help file:
http://thebuildingcoder.typepad.com/blog/2012/05/edit-family-requires-no-transaction.html
Close the transaction before calling EditFamily, or, in this case, don't open it at all to start with.
Oh, and then, of course, you wish to modify the family document. That will indeed require a transaction, but on the family document 'familyDoc', NOT on the project document 'doc'.
I don't know whether this will be the final solution, but it might help:
familyDoc = doc.EditFamily(familySymbol)
TransactionManager.Instance.EnsureInTransaction(familyDoc)
OUT = familyDoc.FamilyManager.AddParameter(par_name,par_grp,par_type,False)
TransactionManager.Instance.TransactionTaskDone()

Resources