How to update embedded column's property in orientdb - 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)

Related

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

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.

Postgres jsonb_set concatenate current value

I'm trying to use jsonb_set to update a range of json objects within my database. I can get a query working that updates the object with a string value, however I cannot seem to get it to update using the current value.
UPDATE entity
SET properties = jsonb_set(properties, '{c_number}', concat('0', properties->>'c_number'))
WHERE type = 1 and length(properties->>'c_number') = 7
The above doesn't work in its current format, I think the issue is the properties->>'c_number' inside the jsonb_set. Is there a way I can access the current value and simply add a leading 0?
Found a solution:
UPDATE entity
SET properties = jsonb_set(properties, '{c_number}', concat('"0', properties->>'c_number', '"')::jsonb)
WHERE type = 1 and length(properties->>'c_number') = 7
Based on this answer I was able to prepare my solution.
My goal was to create a new property in JSON, with a value that is based on the value of one of the properties which my JSON already has.
For example:
I have:
{
property_root: { property_root_child: { source_property_key: "source_property_value" } }
}
I want:
{
property_root: { property_root_child: { source_property_key: "source_property_value", target_property_key: "source_property_value + my custom ending" } }
}
So my query would look:
UPDATE database.table_with_json
SET json_column=jsonb_set(
json_column,
'{ property_root, property_root_child, target_property_key }',
concat('"', json_column->'property_root'->'property_root_child'->>'source_property_key', ' + my custom ending', '"')::jsonb)
WHERE
json_column->'property_root'->'property_root_child'->'source_property_key' IS NOT NULL
Why concat looks messy? Based on the answer mentioned above:
The third argument of jsonb_set() should be of jsonb type. The problem is in casting a text string to jsonb string, you need a string in double quotes.
That is why we have to wrap concat in double qoutes.

Update work item relations/links in VS Team Services

I am trying to use the VSTS API to remove all parent links on items, and set those parents as related items.
https://www.visualstudio.com/en-us/docs/integrate/api/wit/work-items#update-work-items
I do not fully understand how the "Path" needed to remove relations work – I am getting inconsistent results where sometimes it works, sometimes not (so, im clearly doing it wrong)
I am making an assumption that its simply the order returned by the API. So, for example:
Index[0] item
Index[1] item
Index[2] item <- this is the one I want to remove, so I use index 2
public void RemoveParentLink(int pathIndex, int itemToUpdate, string link)
{
JsonPatchDocument patchDocument = new JsonPatchDocument();
patchDocument.Add(
new JsonPatchOperation()
{
Operation = Operation.Remove,
Path = $"/relations/{pathIndex}"
}
);
WorkItem result = witClient.UpdateWorkItemAsync(patchDocument, itemToUpdate).Result;
}
The documentation states that Path is:
Path to the value you want to add, replace, remove, or test.
For a specific relation, use "relations/Id".
For all relations, use "/relations/-".
Index is NOT the Id of course, but how do I get the relation/Id exactly?
Using GetWorkItemAsync or GetWorkItemsAsync with WorkItemExpand.Relations parameter to get linked work items.
Var workItem=witClient.GetWorkItemAsync(id: [work item id], expand: Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models.WorkItemExpand.Relations).Result.
Then the index is the index of relations.
The 'id' in the '/relation/id' path is a index in fact. You retrieve the work item definition, then the 'id' is the index of the link in the 'relations' array. Hence your assumption is right.
Evidence: given a work item with 2 links, if you try to delete/modify id >= 2 it will answer with:
{ "$id": "1", "innerException": null, "message": "Index out of range
for path /relations/2.", "typeName":
"Microsoft.VisualStudio.Services.WebApi.Patch.PatchOperationFailedException,
Microsoft.VisualStudio.Services.WebApi, Version=14.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "typeKey":
"PatchOperationFailedException", "errorCode": 0, "eventId": 3000 }
0 and 1 as id work just fine instead.
I may be wrong, but I could guess that you could get an error when using the 'replace' operation before the 'add' operation. For example you need to add a 'comment' inside the 'attributes' of a link before modifying (i.e. 'replace' operation) its value.

Moped: get id after inserting

When I use mongo-ruby-driver and I insert new document it returns generated '_id':
db = MongoClient.new('127.0.0.1', '27017').db('ruby-mongo-examples')
id = db['test'].insert({name: 'example'})
# BSON::ObjectId('54f88b01ab8bae12b2000001')
I'm trying to get the '_id' of a document after doing an insertion using Moped:
db = Moped::Session.new(['127.0.0.1:27017'])
db.use('ruby-mongo-examples')
id = db['coll'].insert({name: 'example'})
# {"connectionId"=>15, "n"=>0, "syncMillis"=>0, "writtenTo"=>nil, "err"=>nil, "ok"=>1.0}
How I get the id using Moped?
Update:
I also try use safe mode but it doesn't work:
db = Moped::Session.new(['127.0.0.1:27017'])
db.use('ruby-mongo-examples')
db.with(safe: true) do |safe|
id = safe['coll'].insert({name: 'example'})
# {"connectionId"=>5, "n"=>0, "syncMillis"=>0, "writtenTo"=>nil, "err"=>nil, "ok"=>1.0}
end
After inserting/saving, the returned object will have a property inserted_id which is a BSON::ObjectId:
# I'm using insert_one
result = safe['coll'].insert_one({name: 'example'})
result.methods.sort # see list of methods/properties
result.inserted_id
result.inserted_id.to_s # convert to string
From this issue:
It would be nice, but unfortunately Mongo doesn't give us anything
back when inserting (since it's fire and forget), and when in safe
mode it still doesn't give the id back if it generated it on the
server. So there really isn't any possible way for us to do this
unless it was a core feature in MongoDB.
Your best bet would be to generate the id before inserting the document:
document = { _id: Moped::BSON::ObjectId.new, name: "example" }
id = document[:_id]

Possible bug in breeze 1.4.14

I haven't tested this against the 1.4.16 release that came out a couple of weeks ago but there is nothing in the release notes about it.
The problem occurs with predicates where the value you are comparing is identical to the name of a property on any entity that breeze knows about. A simple test case is :
var query = breeze.EntityQuery.from('Items');
var pred = breeze.Predicate.create('name', breeze.FilterQueryOp.Contains, searchTerm);
query = query.where(pred);
Where searchTerm is equal to any string other than "name" this produces an oData query as below:
Items?$filter=(substringof(%27somevalue%27%2CName)%20eq%20true)
but if searchTerm = "name" then it produces the following query
Items?$filter=(substringof(Name%2CName)%20eq%20true)
Which istead of comparing the string 'name' against the property Name, it compares the property Name with itself.
I have not tested every operator but as far as I can tell it does not matter which you use you get the same behaviour.
You also get the same problem when querying navigation properties but it usually results in an invalid query. Below is a predicate for the same entity but against a navigation property tags that contains a collection of ItemTag entities that have a "Tag" property on them.
breeze.Predicate.create('tags', breeze.filterQueryOp.Any, 'tag', breeze.filterQueryOp.Contains, searchTerm)
It works fine for any searchTerm other than "tag" where it produces an oData request as below:
Items?$filter=Tags%2Fany(x1%3A%20substringof(%27somevalue%27%2Cx1%2FTag)%20eq%20true)
but if the searchTerm is "tag" then it requests:
Items?$filter=Tags%2Fany(x1%3A%20substringof(Tag%2Cx1%2FTag)%20eq%20true)
which produces an error of "Could not find a property named 'Tag' on type 'Item'" because the property Tag exists on the ItemTag entity.
In short breeze seems to infer that any search term that is identical to the name of a property it knows about, refers to that property rather than being a string literal value.
Has anyone else encountered this?
Is this a bug, or is there a way to explicitly tell breeze to interpret that value as a string literal and not a reference to a property?
I am not sure it is relevant as the server seems to be responding correctly to the requests and it is breeze that is creating incorrect requests but on the server side I am using Web API oData controllers with EF as ORM data layer.
Try
var pred = breeze.Predicate.create('name', breeze.FilterQueryOp.Contains,
{ value: searchTerm, isLiteral: true} );
This is described here ( under the explanation of the value parameter):
http://www.breezejs.com/sites/all/apidocs/classes/Predicate.html#method_create
if the value can be interpreted as a property expression it will be, otherwise it will be treated as a literal.
In most cases this works well, but you can also force the interpretation by making the value argument itself an object with a 'value' property and an 'isLiteral' property set to either true or false.
Breeze also tries to infer the dataType of any literal based on context, if this fails you can force this inference by making the value argument an object with a 'value' property and a 'dataType'property set
to one of the breeze.DataType enumeration instances.
The reason for this logic is to allow expressions where both sides of the expression are properties. For example to query for employees with the same first and last name you'd do this:
var q = EntityQuery.from("Employees")
.where("lastName", "==", "firstName");
whereas if you wanted employees with a lastName of 'firstName' you'd do this:
var q = EntityQuery.from("Employees")
.where("lastName", "startsWith", { value: "firstName", isLiteral: true })