When I run the following:
search_doc = Document.search(
using=client,
index=custom_index
)
search_doc = search_doc.query("term", doc_field = f"string_{num}")
and then use .scan() I get Hit objects. So, something seems to be wrong...
However, when I use the ids of those hit objects:
all_docs = [doc.meta.id for doc in search_doc.scan()]
for id in all_docs:
loc = Document.get(
using=client,
index=custom_index,
id = id
)
assert isinstance(doc, Document) # <- always true!!
Why is there this difference? Why doesn't the search object return documents objects?
Here's the definition of my Document class:
field_1 = dsl.Keyword()
field_2 = dsl.Keyword(multi=True)
data = dsl.Object(Inner_Document) # data will have many other fields
last_updated = dsl.Date()
class Index:
name = default_index # different from custom_index
settings = {
"number_of_shards": 1
}
class Meta:
dynamic = dsl.MetaField('strict')
The version of ES that I'm using is 7.17.6 .
The package elasticsearch is 7.17.3
and elasticsearch-dsl is 7.4.0 .
Related
#hybrid_method
# #paginate
def investors(self, **kwargs):
"""All investors for a given Custodian"""
ind_inv_type_id = InvestorType.where(description="Individual").first().id
inv_query = Investor.with_joined(InvestorAddress, InvestmentAddress, CustodianAddress) \
.filter_by(custodians_id=self.id) \
.with_joined(Investment) \
.filter_by(investor_types_id=ind_inv_type_id)
investors = Investor.where(None, False, inv_query, **kwargs)
temp_inv_query = Investor.with_joined(CustodianInvestor, Custodian)\
.filter_by(Custodian.id==self.id)
temp_investors = Investor.where(None, False, temp_inv_query, **kwargs)
return list(set(investors + temp_investors))
# end def investors
# #auth.access_controlled
class InvestorAddress(db.Model, EntityAddressMixin):
# Metadata
__tablename__ = 'investor_addresses'
# Database Columns
investors_id = db.Column(db.ForeignKey("investors.investors_id"),
nullable=False)
investor = db.relationship("Investor", foreign_keys=[investors_id],
backref=db.backref("InvestorAddress"))
# end class InvestorAddress
class InvestmentAddress(db.Model):
"""This model differs from other EntityAddress Models because it links to either an investor_address or an custodian_address."""
# Metadata
__tablename__ = 'investment_addresses'
# Database Columns
address_types_id = db.Column(
db.ForeignKey("address_types.address_types_id"),
nullable=False)
address_type = db.relationship("AddressType",
foreign_keys=[address_types_id],
backref=db.backref("InvestmentAddress"))
investments_id = db.Column(db.ForeignKey("investments.investments_id"),
nullable=False)
investment = db.relationship("Investment",
foreign_keys=[investments_id],
backref=db.backref("InvestmentAddress"))
investor_addresses_id = db.Column(db.ForeignKey(
"investor_addresses.investor_addresses_id"))
investor_address = db.relationship("InvestorAddress",
foreign_keys=[investor_addresses_id],
backref=db.backref("InvestmentAddress"))
custodian_addresses_id = db.Column(db.ForeignKey(
"custodian_addresses.custodian_addresses_id"))
custodian_address = db.relationship("CustodianAddress",
foreign_keys=[custodian_addresses_id],
backref=db.backref("InvestmentAddress")
)
# end class InvestmentAddress
class CustodianAddress(db.Model, EntityAddressMixin):
"""Defines the relationship between a Custodian and their addresses."""
# Metadata
__tablename__ = 'custodian_addresses'
# Database Columns
custodians_id = db.Column(db.ForeignKey(
"custodians.custodians_id"), nullable=False)
custodian = db.relationship("Custodian", foreign_keys=[custodians_id],
backref=db.backref("CustodianAddress"))
# end CustodianAddress
i have an application and this function is supposed to return a list of 'investors' for a given 'Custodian'. Now when it executes i get an error: "sqlalchemy.exc.ArgumentError: mapper option expects string key or list of attributes". The error comes from the 'join' in the 'inv_query'.
I have included my 3 models that im using for the Join.
As described in the documentation provided by you. here
You should provide string arguments(table names) in with_joined. Given you have defined the relationship
Investor.with_joined('investorAddressTable', 'investmentAddressTable, 'custodianAddressTable')
In case you can use session then you can query the ORM classes directly like
session.query(Investor).join(InvestorAddress).join(InvestmentAddress).join(CustodianAddress).all() # will assume you have set the foreign key properly
I'm developing a map site using Google App Engine with Python language, and have used Search API to apply to my site (https://cloud.google.com/appengine/training/fts_intro/lesson2). How i get doccument id after put it in an index? I did as below but not get the doc_id:
fields = [
search.TextField(name = 'userid', value = request.userid),
search.NumberField(name = 'zoom', value = request.zoom),
search.TextField(name = 'title', value = request.title),
search.TextField(name = 'content', value = request.content),
search.GeoField(name = 'location', value = search.GeoPoint(request.lat, request.lng))
]
d = search.Document(fields = fields)
search.Index(name = _INDEX_NAME).put(d)
doc_id = d.doc_id
See the full documentation:
results = search.Index(name=_INDEX_NAME).put(d)
doc_id = results[0].id
I have two collections ScenarioDrivers and ModelDrivers which has One to Many relationship with each other.
class ScenarioDrivers(Document):
meta = {
'collection': 'ScenarioDrivers'
}
ScenarioId = ReferenceField('ModelScenarios')
DriverId = ReferenceField('ModelDrivers')
DriverCalibrationMethod = StringField()
SegmentName = StringField()
DriverValue = ListField()
CalibrationStatus = StringField()
AdjustedValues = ListField(default=[])
CreateDate = DateTimeField(default=ObjectId().generation_time)
LastUpdateDate = DateTimeField(default=datetime.utcnow())
class ModelDrivers(Document):
meta = {
'collection': 'ModelDrivers'
}
PortfolioModelId = ReferenceField('PortfolioModels')
DriverName = StringField()
CreateDate = DateTimeField(default=ObjectId().generation_time)
LastUpdateDate = DateTimeField(default=datetime.utcnow())
FieldFormat = StringField()
DriverData = ListField()
My query is like this.
class GetCalibratedDrivers(Resource):
def get(self, scenario_id):
scenario_drivers_list = []
scenario_drivers = ScenarioDrivers.objects(ScenarioId=scenario_id).exclude('ScenarioId').select_related(1)
for scenario_driver in scenario_drivers:
scenario_driver_dict = {
'id': str(scenario_driver.id),
'DriverId': str(scenario_driver.DriverId.id),
'SegmentName': scenario_driver.SegmentName,
'CalibrationMethod': scenario_driver.DriverCalibrationMethod,
'CalibratedValues': exchange(scenario_driver.DriverValue),
'AdjustedValues': scenario_driver.AdjustedValues,
'LastUpdateDate': formatted_date(scenario_driver.LastUpdateDate),
'FieldFormat': scenario_driver.DriverId.FieldFormat
}
scenario_drivers_list.append(scenario_driver_dict)
return {
'DriverCalibrations': scenario_drivers_list
}
The Query matches 1140 records and then I construct a dictionary and make it a list.
But this API call takes 30s to process just 1140 records. Where I am missing? Please help. I am using latest version of Pymongo and MongoEngine.
I think the problem is not with your query, it is with you looping over 1140 records. I do not see any use of referenced objects so you should consider removing select_related(1). Once you do that, if you want to convert reference object ids to string, you can use as_pymongo() which will do that by default for you. And finally if you must read some data in specific format like formatted_date or exchange, it is better to save them as part of your document. i.e. save FormattedLastUpdateDate with LastUpdateDate. In MongoDB, you have to think about your read specific logic when you save the document.
For unknown reasons, I cannot assign a foreign key instance of Item_rarity table into Detailed_item table. Django throws an error:
Cannot assign "u'Basic'": "Detailed_item.rarity" must be a "Item_rarity" instance.
... But in Item_rarity dictionary "Basic" record exists - I can choose it from admin panel and create Detailed_item record manually.
I have defined models:
class Detailed_item(models.Model):
item_id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=50)
level = models.IntegerField()
icon = models.CharField(max_length=150)
rarity = models.ForeignKey('Item_rarity')
general_type = models.ForeignKey('Item_type')
detailed_type = models.ForeignKey('Item_detailed_type')
class Item_rarity(models.Model):
name = models.CharField(max_length=15, primary_key=True)
class Item_type(models.Model):
name = models.CharField(max_length=15, primary_key=True)
class Item_detailed_type(models.Model):
name = models.CharField(max_length=20, primary_key=True)
In views, I try to populate it in this manner (inserting multiple items):
...
items = get_all_items() #get dict of items
for element in items:
tmp_det_type = ''
for key, val in element.iteritems():
#get 'detailed type' from inner dict
if key == "type":
tmp_det_type = val
item = Detailed_item(
item_id=element['id'],
name=element['name'],
level=element['level'],
icon=element['icon'],
rarity=element['rarity'], #error
general_type=element['type'],
detailed_type=tmp_det_type,
)
item.save()
...
I even tried to hard code "Basic" string, but it doesn't work either.
* Solved *
Next two entries, that is Item_type and Item_detailed_type were also invalid.
Correct code:
from app.models import Detailed_item, Item_rarity, Item_type, Item_detailed_type
...
items = get_all_items() #get dict of items
for element in items:
tmp_det_type = ''
for key, val in element.iteritems():
#get 'detailed type' from inner dict
if key == "type":
tmp_det_type = val
#create objects with string values
obj_rarity = Item_rarity(name=element['rarity'])
obj_item_type = Item_type(name=element['type'])
obj_item_detailed_type = Item_detailed_type(name=tmp_det_type)
item = Detailed_item(
item_id=element['id'],
name=element['name'],
level=element['level'],
icon=element['icon'],
rarity=obj_rarity,
general_type=obj_item_type,
detailed_type=obj_item_detailed_type,
)
item.save()
...
Item_rarity instance should be passed while storing Detailed_item object since Item_rarity is a foreign key related object in Detailed_item.
Its that you might have passed the Basic string instead of the <Basic Object> itself.
While creating an object in django using its ORM, any foreign_key related object should be provided with the instance itself instead of the id(pk) of the object, where as while fetching the data from the database you can use either of instance or the id(pk) of the instance.
class ParentModel(models.Model):
model_field = models.CharField(max_length=16)
class MyModel(models.Model):
some_field = models.ForeignKey('ParentModel')
parent_model = ParentModel.objects.create(model_field='some_data')
my_model = MyModel.objects.create(some_field=parent_model)
^^^^^^^^^^^^
Note here that the parent_model object itself is passed instead of the id
While fetching the data back,
parent_model = ParentModel.objects.get(model_field='some_data')
my_model = MyModel.objects.get(some_field=parent_model)
or
my_model = MyModel.objects.get(some_field=parent_model.id)
Both would work in case of data fetch.
You do not have to provide the related object on creation if you change the kwarg in to rarity_name:
item = Detailed_item(
item_id=element['id'],
name=element['name'],
level=element['level'],
icon=element['icon'],
rarity_name=element['rarity'], # no error
general_type=element['type'],
detailed_type=tmp_det_type,
)
I have only tested this with the regular id field (the auto pk) but it
should work with your primary key just fine.
E.g.
class SimpleModel(Model):
value = TextField(blank=True)
class ComplexModel(Model):
simple = ForeingKey(SimpleModel)
title = TextField(unique=True)
ComplexModel.objects.create(title='test', simple_id=1)
I'm writing a python script to populate a mongodb database, my models look like the following:
from mongoengine import *
from mongoengine.django.auth import User
class TrackGroup (Document):
name = StringField(required=True)
users = ListField(ReferenceField('User'))
devices = ListField(ReferenceField('Device'))
class Device(Document):
name = StringField(max_length=50, required=True)
grp = ListField(ReferenceField(TrackGroup))
class User(User):
first_name = StringField(max_length=50)
last_name = StringField(max_length=50)
grp = ListField(ReferenceField(TrackGroup))
And my script goes like this:
#Create a group
gName = 'group name'
g = TrackGroup(name=gName)
g.users = []
g.devices = []
g.save()
#create a user
u = User.create_user(username='name', password='admin', email='mail#ex.com')
gRef = g
u.grp = [gRef, ]
u.first_name = 'first'
u.last_name = 'last'
u.save()
gRef.users.append(u)
gRef.save()
#create a device
dev = Device(name='name').save()
gRef = g
dev.grp = [gRef, ]
dev.save()
gRef.devices.append(dev)
gRef.save() #Problem happens here
The problem happens when I call gRef.save() I get the following error:
raise OperationError(message % unicode(err))
mongoengine.errors.OperationError: Could not save document (LEFT_SUBFIELD only supports Object: users.0 not: 7)
I looked around for a while, and here it says that this means I'm trying to set a filed with an empty key, like this: (The example is from the link above, not mine)
{
"_id" : ObjectId("4e52b5e08ead0e3853320000"),
"title" : "Something",
"url" : "http://www.website.org",
"" : "",
"tags" : [ "international"]
}
I don't know where such a field can come from, but I opened a mongo shell and looked at my documents from the three collections, and I couldn't find such a field.
Note: If I add the device first, the same error occurs while saving the group after adding the user.
I had the same error, and this trick work for me:
the_obj_causing_error.reload()
/* make some change */
the_obj_causing_error.price = 5
the_obj_causing_error.save()
just try reload() the object before changing it.