How to update DB when field changed in mongoalchemy.(flask)? - mongodb

I am using flask-mongoalchemy to do a demo, and here is a question confused me for a while.
At first I create a class User
class Student(db.Document):
'''student info'''
name = db.StringField()
grade = db.IntField(required=False, default=None)
Then, I use this DB and create some example, such as student1, student2...and so on。
Now, I change the default value of grade from None to 0
grade = db.IntField(required=False, default=0)
When I run query again, it raise error:
mongoalchemy.exceptions.BadValueException: Bad value for field of type "grade". Reason: "Value is not an instance of <class 'int'>
SO, how to auto-update this field change? What I did now is to modify the value of age in database manualy.

First, to get the queries working as before set allow_none option on the field to True.
grade = db.IntField(required=False, default=0, allow_none=True)
That should allow documents having no value for grades to not trigger errors when unwrapped as python objects.
Next, make a migration that sets the default value for documents where grade is None to 0.
from mongoalchemy.session import Session
with Session.connect('mongoalchemy') as s:
update = s.query(Student).filter(Student.grade == None).set(User.grade, 0)
update.execute()
Lastly, switch the field declaration back to disallow None values for the grade.

Related

HTTP PATCH method in golang

I am implementing a HTTP PATCH method in golang and postgresql, I need to read the data from the request and update the data provided into the postgresql.
The method works fine if all the values of the struct is provided, but if only partial data is given to a request, the other fields are becoming empty. Can anyone please help me out to deal this problem.
type StudentDetails struct {
Id int `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
Class int `json:"class"`
}
Query which I am using "UPDATE table_name SET name=$2, age=$3, class=$4 WHERE id=$1"
If all the fields given in the request this works fine, but if I need to update only the AGE and the request json would be {"age": 10} or some other field we dont know. Here Age is set to 10 but remaining all fields will become "" or 0 and that will be updated into the database
Anyone has the solution to this problem, how to update the requested field only and not change other fields.
I have approached using a separate query for all fields, but I think its not the proper one. Please give me a solution
Like what #David Hall said in the comments, use pointer to a type in the fields of your struct. See example below:
type ArticleModel struct {
gorm.Model
ID uuid.UUID `gorm:"primaryKey;type:uuid"`
Title *string
Body *string
}
I am using gorm, then when unmarshalling the json from http request you will get nil value if not provided. You need to add nil checkers to skip in the construction of your SQL query. Something like this.
if entity.Title != nil {
model.Title = entity.Title
}
if entity.Body != nil {
model.Body = entity.Body
}
db.Save(&model)
Now the next problem would be how to intentionally empty the field in database (explicitly nulling the value) like UPDATE table SET field = null. Unfortunately I haven't figured it out also.
What I have in mind is checking if empty string and considering it as the setting it to empty value. Although I want to see better options.

EF Core completely ignores my selected properties in select

As I understand it, the following code should generate a query containing only the RouteId, RouteNo, and ShipId
var tow = (from t in _context.AllTowData
where t.RouteId == id
orderby t.RouteNo descending
select new TowDefaults {
Id = t.RouteId,
TowNo = t.RouteNo,
ShipId = t.ShipId,
LastTow = t.RouteNo
})
.FirstOrDefault();
However, I get:
SELECT v.route_id, v.route_no, v.tow_id, v.analysis_complete, v.checks_complete, v.cpr_id, v.date_created, v.date_last_modified, v.factor, v.fromportname, v.instrument_data_file, v.instrument_id, v.internal_number, v.mastername, v.message, v.miles_per_division, v.month, v.number_of_samples, v.number_of_samples_analysed_fully, v.prop_setting, v.route_status, v.sampled_mileage, v.serial_no_per_calendar_month, v.ship_speed, v.silk_reading_end, v.silk_reading_start, v.toportname, v.tow_mileage, v.validity, v.year
FROM view_all_tow_data AS v
WHERE v.route_id = '#__id_0'
ORDER BY v.route_no DESC
LIMIT 1
That's every column except the explicitly requested ShipId! What am I doing wrong?
This happens using both a SQL Server and a PostGres database
The property ShipIdis not mapped, either by a [NotMapped] annotation or a mapping instruction. As far as EF is concerned, the property doesn't exist. This has two effects:
EF "notices" that there's an unknown part the final Select and it switches to client-side evaluation (because it's a final Select). Which means: it translates the query before the Select into SQL which doesn't contain the ShipId column, executes it, and materializes full AllTowData entities.
It evaluates the Select client-side and returns the requested TowDefaults objects in which ShipId has its default value, or any value you initialize in C# code, but nothing from the database.
You can verify this by checking _context.AllTowData.Local after the query: it will contain all AllTowData entities that pass the filter.
From your question it's impossible to tell what you should do. Maybe you can map the property to a column in the view. If not, you should remove it from the LINQ query. Using it in LINQ anywhere but in a final Select will cause a runtime exception.

mybatis - Passing multiple parameters on #One annotation

I am trying to access a table in my Secondary DB whose name I am obtaining from my Primary DB. My difficulty is to pass the "DB-Name" as a parameter into my secondary query, (BTW I am using MyBatis annotation based Mappers).
This is my Mapper
#SelectProvider(type = DealerQueryBuilder.class, method = "retrieveDealerListQuery")
#Results({
#Result(property="dealerID", column="frm_dealer_master_id"),
#Result(property="dealerTypeID", column="frm_dealer_type_id", one=#One(select="retrieveDealerTypeDAO")),
#Result(property="dealerName", column="frm_dealer_name")
})
public List<Dealer> retrieveDealerListDAO(#Param("firmDBName") String firmDBName);
#Select("SELECT * from ${firmDBName}.frm_dealer_type where frm_dealer_type_id=#{frm_dealer_type_id}")
#Results({
#Result(property="dealerTypeID", column="frm_dealer_type_id"),
#Result(property="dealerType", column="frm_dealer_type")
})
public DealerType retrieveDealerTypeDAO(#Param("firmDBName") String firmDBName, #Param("frm_dealer_type_id") int frm_dealer_type_id);
The firmDBName I have is obtained from my "Primary DB".
If I omit ${firmDBName} in my second query, the query is trying to access my Primary Database and throws out table "PrimaryDB.frm_dealer_type" not found. So it is basically trying to search for a table named "frm_dealer_type" in my Primary DB.
If I try to re-write the #Result like
#Result(property="dealerTypeID", column="firmDBName=firmDBName, frm_dealer_type_id=frm_dealer_type_id", one=#One(select="retrieveDealerTypeDAO")),
It throws an error that Column"firmDBName" does not exist.
Changing ${firmDBName} to #{firmDBName} also did not help.
I did refer to this blog - here
I want a solution to pass my parameter firmDBName from my primary query into secondary query.
The limitation here is that your column must be returned by the first #SELECT.
If you look at the test case here you will see that parent_xxx values returned by the first Select.
Your DealerQueryBuilder must select firmDBName as a return value and your column must map the name of the return column to that.
Your column definition is always wrong, it should be:
{frm_dealer_type_id=frm_dealer_type_id,firmDBName=firmDBName} or whatever it was returned as from your first select.
Again you can refer to the test case I have above as well as the documentation here http://www.mybatis.org/mybatis-3/sqlmap-xml.html#Nested_Select_for_Association

How to update embedded column's property in orientdb

I am facing an issue while updating an embedded field's property in Orientdb.
Below are the steps to reproduce the issue:
CREATE VERTEX Foo set value = { 'abc-def-hgi':"blah blah", '1ab-2cd-3ef': "aaaaa", '345-jkl-mno':'ppppp' }, id = 1
CREATE VERTEX Foo set value = { 'abc-def-hgi':"mmmmm", '1ab-2cd-3ef': "nmnmnmn", '345-jkl-mno':'qqqq' }, id = 2
CREATE VERTEX Foo set value = { 'abc-def-hgi':"lorem ipsum", '1ab-2cd-3ef': "mmmmm", '345-jkl-mno':'llll' }, id = 3
Property "value" has been declared as of type "Embedded".
Now, I want to update record with id "1" for "abc-def-hgi" property in column "value".
I have tried with below queries, but neither of them worked:
update Foo set value["abc-def-hgi"] = "new new" where id = 1
update Foo set value.abc-def-hgi = "new new" where id = 1
It seems that it is having problem with hypen ("-") in the field's property name.
I am using Orientdb's version: 2.2.11
Note: I have looked upon issues in orientdb Git repo, where I found this. Not sure whether it is related to my issue or not, but it's not working at my end.
Any help would be great appreciated.
As you said yourself the problem is with -.
If you try with a field without - the following query works.
Example
update Foo set value.prop = "myprop1" where id=1
If you try to create a field with - , you got an exception.
UPDATE
To create a property with hyphen you could use this command
create property foo.`abc-def-hgi` string
Hope it helps
Regarding the usage of '-' in the names of the properties you can use the quotes as Alessandro says or disable the "Strict" value in database option (in that case you are rolling back to the old parser that was a little bit less rigid)

Pass nothing (not null) to the server if the argument is None

I have a model:
case class MyModel(
id: Pk[Long] = NotAssigned,
startsAt: Option[DateTime] = None,
addedAt: Option[DateTime] = None
)
object MyModel {
// .....................
SQL("""
INSERT INTO my_table(starts_at)
VALUES ({startsAt})
"""
).on('startsAt -> newItem.startsAt).executeInsert()
}
Both startst_at and added_at have a default value of now() in Postgresql and don't allow null values in them. It doesn't cause any error for addedAt (because I never pass it to the server from the client) but it does cause the error for startsAt if it's not specified at newItem.startsAt and, thus, is equal to None and, thus, it's being passed as null.
org.postgresql.util.PSQLException: ERROR: null value in column "starts_at" violates not-null constraint
What I want is be able to specify startsAt whenever I want it and pass it to the server, meaning if I specify it then that value should be passed to the server, if not - nothing should be passed and the server should use its default value now(). I don't want to specify the default value at the client because it's already set at the server at the db level.
How about this SQL fix:
insert into my_table(starts_at)
values (COALESCE({startsAt}, now())
Updated: requirement is to use the default value of the column
The only way that I know of to get the server to use the default value of a column in an insert, is not to mention that column in the columns list. For example (not tested):
startsAt.map { date =>
SQL("""insert into my_table(starts_at) values({startsAt})""")
.on('startsAt -> date)
.execute()
}.orElse {
SQL("""insert into my_table() values()""")
.execute()
}