Azure CosmosDb Gremlin API, Clone vertex, Compilation Error - azure-cosmosdb

Based on this answer provided by daniel-luppitz, I am trying to clone a vertex in Azure CosmosDb but I am getting the following error:
Compilation Error: Unable to bind to method 'property', with arguments of type: (GraphTraversal,GraphTraversal)
The query:
IGraphTraversalSource g = coreClient.CreateTraversalSource();
ITraversal query = g.V(new PartitionKeyIdPair(pk, id)).As("source")
.AddV("clone").Property("partitionKey", pk).As("clone")
.SideEffect(__.Select<User>("source").Properties<String>().As("p").Select<User>("clone")
.Property(__.Select<object>("p").Key(), __.Select<string>("p").Value<string>()))
If I change the key and value traversals
.Property(__.Select<object>("p").Key(), __.Select<string>("p").Value<string>()
to constant values then the query works
.Property("test", "test")
Any idea how to achieve this in Azure CosmosDb?

I'm not sure which TinkerPop version is currently supported by Cosmos DB, but after skimming through the docs, I would say it's something close to 3.2.5. The 3.2 line did not support dynamic keys/values, that was added somewhere along the 3.3 line.
Thus, the only way to do that in Cosmos DB would be to split the query. Get the values you need and then submit follow-up queries based on the gathered values. Obviously, this won't perform very well will probably increase your usage costs dramatically, but I can't think of another way of doing it using old Gremlin versions (considering that lambdas are another thing that's not supported in Cosmos DB).

Related

Azure cosmosDB gremlin - how to update vertex property with another vertex's property

On an Azure cosmosDB gremlin instance,
I have 2 vertices A and B linked by and edge E.
Both vertices has a 'name' property.
I'd like to run a query which will take A's name and put it in B
when I run
g.V("AId").as("a").oute().inv().hasLabel('B').property("name",select('a').values('name'))
I get the following error :
GraphRuntimeException ExceptionMessage : Gremlin Query Execution Error: Cannot create ValueField on non-primitive type GraphTraversal.
It looks like the select operator is not correctly used.
Thank you for your help
EDITED based on discussion in comments
You have oute and inv in lower case. In general, the steps use camelCase naming, such as outE and inV (outside of specific GLVs), but in the comments it was mentioned that CosmosDB will accept all lower case step names. Assuming therefore, that is not the issue here, the query as written looks fine in terms of generic Gremlin. The example below was run using TinkerGraph, and uses the same select mechanism to pick the property value.
gremlin> g.V(3).as("a").outE().inV().has('code','LHR').property("name",select('a').values('city'))
==>v[49]
gremlin> g.V(49).values('name')
==>Austin
What you are observing may be specific to CosmosDB and it's probably worth contacting their support folks to double check.

Create Vertex only if "from" and "to" vertex exists

I want to create 1000+ Edges in a single query.
Currently, I am using the AWS Neptune database and gremlin.net for creating it.
The issue I am facing is related to the speed. It took huge time because of HTTP requests.
So I am planning to combine all of my queries in a string and executing in a single shot.
_g.AddE("allow").From(_g.V().HasLabel('person').Has('name', 'name1')).To(_g.V().HasLabel('phone').Where(__.Out().Has('sensor', 'nfc'))).Next();
There are chances that the "To" (target) Vertex may not be available in the database. When it is the case this query fails as well. So I had to apply a check if that vertex exists before executing this query using hasNext().
So as of now its working fine, but when I am thinking of combining all 1000+ edge creation at once, is it possible to write a query which doesn't break if "To" (target) Vertex not found?
You should look at using the Element Existence pattern for each vertex as shown in the TinkerPop Recipes.
In your example you would replace this section of your query:
_g.V().HasLabel('person').Has('name', 'name1')
with something like this (I don't have a .NET environment to test the syntax):
__.V().Has('person', 'name', 'name1').Fold().
coalesce(__.Unfold(), __.AddV('person').Property('name', 'name1')
This will act as an Upsert and either return the existing vertex or add a new one with the name property. This same pattern can then be used on your To step to ensure that it exists before the edge is created as well.

Azure Cosmos DB: Update pipeline supported, or Cosmos-native way to emulate this?

We wanted to switch over from using MongoDB 4.2 to Cosmos DB, but realized that the thing preventing us to do so are Update (aggregation) Pipelines. MongoDB supports them, on Cosmos DB we get a weird looking error Expected type object but found array. which prompts us to believe they are not supported (as you provide an array of update stages as opposed to an update document).
Is there a way to achieve something similar with Cosmos DB methods?
Update pipelines in MongoDB allow you to update a document with multiple steps as one atomic operation. The pipeline currently looks kinda like this (stock-keeping system with keeping track of reservations):
Set a field to a value, and set another field to a calculated
value based on some input and some document fields
Set a boolean flag in case the calculation from step 1 yielded 0 or less
Set a DateTime flag to NOW in case calculation from step 2 triggered
"false"

Using the sort() cursor method without the default indexing policy in Azure Cosmos DB for MongoDB API

With Cosmos DB for MongoDB API (Version 3.4), the following find query in combination with the method cursor sort seems to behave incorrectly:
db.test.find({"field1": "value1"}).sort({"field2": 1})
The error occurs, if all of the following conditions are met:
the default indexing policy were discarded - regardless of whether custom indexes were created afterwards using createIndex().
The find() query does not return any documents (Find(filter).Count() == 0)
The Sort document defining the sort order contains only one field. It doesn't matter, whether this field exists or has been indexed. Using two fields in the sort document returns 0 hits which is the correct behavior.
The error also occurs, if all of the following conditions are met:
the default indexing policy were discarded
The find() query returns one or more documents
The Sort document contains exactly one field. This field has not been indexed.
The error message:
The index path corresponding to the specified order-by item is excluded.
The malfunction occurs only when using the CosmosDB, with native MongoDB (mongoDB Atlas, v4.0) it behaves correctly.
Azure Cosmos DB for MongoDB API with MongoDB 3.4 wire protocol (preview feature) is used. The problem occurs with both a MongoDB C#/.NET driver and the mongo shell.
In addition, the problem only occurs with find(). An equivalent aggregation pipeline containing $match and $sort behaves correctly.
Reproduction
Create an Azure Cosmos DB Account with the "Azure Cosmos DB for MongoDB API". Enable the preview feature MongoDB 3.4 (Version 3.2 has not been tested).
Create a new database
Create a new collection, define a shard key
Drop the default indexing policy (using db.test.dropIndexes() )
(Optional) Create new custom indexes
(Optional) Insert documents
Execute command in mongo shell (or the equivalent code with mongoDB C#/.NET driver):
db.test.find({"field1": "value1"}).sort({"field2": 1})
Expected result
All documents that match the query criteria. If there are none, no documents should be returned.
Actual result
Error: error: {
"_t" : "OKMongoResponse",
"ok" : 0,
"code" : 2,
"errmsg" : "Message: {\"Errors\":[\"The index path corresponding to the specified order-by item is excluded.\"]}\r\nActivityId: c50cc751-0000-0000-0000-000000000000, Request URI: /apps/[...]/, RequestStats: \r\nRequestStartTime: 2019-07-11T08:58:48.9880813Z, RequestEndTime: 2019-07-11T08:58:49.0081101Z, Number of regions attempted: 1\r\nResponseTime: 2019-07-11T08:58:49.0081101Z, StoreResult: StorePhysicalAddress: rntbd://[...]/, LSN: 359549, GlobalCommittedLsn: 359548, PartitionKeyRangeId: 0, IsValid: True, StatusCode: 400, SubStatusCode: 0, RequestCharge: 1, ItemLSN: -1, SessionToken: -1#359549, UsingLocalLSN: True, TransportException: null, ResourceType: Document, OperationType: Query\r\n, SDK: Microsoft.Azure.Documents.Common/2.4.0.0", [...]
Workaround
Adding an additional "dummy" field to the sort document prevents the error:
db.test.find({"field1": "value1"}).sort({"field2": 1, "dummyfield": 1}).count()
The workaround is not satisfactory. It could falsify the result.
Am I doing something wrong, or is Cosmos DB behaving flawed here?
According to Microsoft support, an index needs to be created on the field being sorted. The default indexes can be dropped and custom indexes created. As for the issue of not modifying the index every time a new field is added, there is no other alternative other than performing a client side sort. Unfortunately, client side sorting would take lot of CPU memory on the client side and the sort on index would take work when you would get more fields to index.
Thus I did not find a really satisfying solution:
Using the Default Indexing Policy. However, this can lead to a huge index.
Indexing all elements that need to be sorted. Every time a new element has to be indexed, this leads to a manual modification of the indexing policy.
Only use Client-side sort. In my opinion this leads to a strong limitation of MongoDB functionality.
Using aggregation frameworks instead of the find method. This leads to increased complexity and traffic.
Migrating to native MongoDB.
db.collection.createIndex ({ "$**" : 1 });

Updating node on Orientdb with gremlin query

I am having trouble updating properties in the nodes in Orientdb using gremlin with the following code. Both property and setProperty doesn't seem to work for OrientDB.
g.V('#rid','#100').property('text','new updated text'))
g.V('#rid','#100').setProperty('text','new updated text'))
However, I was able to update the node using SQL-like query that OrientDB supports.
update classname set text = 'new updated text' where #rid = #100
But I need to update the nodes with using gremlin query in OrientDB. I looked into gremlin query tutorials and most suggest that .property('text','new updated text') should work.
Is it that OrientDB only supports limited gremlin queries and not all?
You seem to have a bit of a mix between TinkerPop 2.x and 3.x syntax. My memory is really hazy about TinkerPop 2.x but I think you just need to iterate your traversal and use the second syntax. Therefore, assuming g.V('#rid','#100') returns a vertex you should just do:
g.V('#rid','#100').next().setProperty('text','new updated text'))

Resources