You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi @prabushitha, thanks for the great work on the visualizer. I had some issues with Microsoft Cosmos DB, because of the executed query ${query}${nodeLimitQuery}.dedup().as('node').project('id', 'label', 'properties', 'edges').by(__.id()).by(__.label()).by(__.valueMap().by(__.unfold())).by(__.outE().project('id', 'from', 'to', 'label', 'properties').by(__.id()).by(__.select('node').id()).by(__.inV().id()).by(__.label()).by(__.valueMap().by(__.unfold())).fold()).
It contains Gremlin constructs not supported by Cthe Cosmos DB Graph implementation of Gremlin: by(__.valueMap().by(__.unfold()).
I created a version that works correctly for Cosmos DB Graph where I did split the query into three different queries to get it working correctly. I also added an additional endpoint in the service to request the incoming and outgoing edges. Because Cosmos B Graph contains an authenticated endpoint I configure the proxy server with an included config.js file:
config.js:
varconfig={}config.endpoint="wss://<yourservername>.gremlin.cosmosdb.azure.com:443/gremlin";config.primaryKey="<your primary key as can be found under keys in Azure>"config.database="<name of the database>";config.collection="<name of the collection>";config.port=3001;module.exports=config;
proxy-server.js:
constexpress=require('express');constbodyParser=require('body-parser');constGremlin=require('gremlin');constcors=require('cors');constapp=express();constfs=require('fs');constpath=require('path');constconfig=require('./config');app.use(cors({credentials: true,}));// parse application/jsonapp.use(bodyParser.json());// Each property has as value an array with length 1 - take first elementfunctionmapVertexPropertiesToObj(propInObj){letpropOutObj={};Object.keys(propInObj).forEach(k=>propOutObj[k]=propInObj[k][0]);returnpropOutObj;}functionedgesToVisualizationStructure(edges){if(!!edges){returnedges.map(edge=>({id: typeofedge.id!=="string" ? JSON.stringify(edge.id) : edge.id,from: edge.from,to: edge.to,label: edge.label,properties: edge.properties,}));}else{return[];}}functionnodesToVisualizationStructure(nodeList){returnnodeList.map(node=>({id: node.id,label: node.label,properties: mapVertexPropertiesToObj(node.properties),edges: edgesToVisualizationStructure(node.edges)}));}functionmakeSelfQuery(query){consttheQuery=`${query}. as('node'). project('id', 'label', 'properties'). by(__.id()). by(__.label()). by(__.valueMap()) `;returntheQuery;}functionmakeInQuery(query,nodeLimit){// original query: `${query}${nodeLimitQuery}.dedup().as('node').project('id', 'label', 'properties', 'edges').by(__.id()).by(__.label()).by(__.valueMap().by(__.unfold())).by(__.outE().project('id', 'from', 'to', 'label', 'properties').by(__.id()).by(__.select('node').id()).by(__.inV().id()).by(__.label()).by(__.valueMap().by(__.unfold())).fold())`;constnodeLimitQuery=!isNaN(nodeLimit)&&Number(nodeLimit)>0 ? `.limit(${nodeLimit})` : '';consttheQuery=`${query}${nodeLimitQuery}. dedup(). as('node'). project('id', 'label', 'properties', 'edges'). by(__.id()). by(__.label()). by(__.valueMap()). by(__.outE().as('outEdge'). project('id', 'from', 'to', 'label', 'properties'). by(__.id()). by(select('node').id()). by(__.inV().id()). by(__.label()). by(__.valueMap()). fold() ) `;// coalesce(select('outEdge').inV().count().is(gt(0)).select('outEdge').inV().id(), constant("NO_TO_VERTEX"))returntheQuery;}functionmakeOutQuery(query,nodeLimit){// original query: `${query}${nodeLimitQuery}.dedup().as('node').project('id', 'label', 'properties', 'edges').by(__.id()).by(__.label()).by(__.valueMap().by(__.unfold())).by(__.outE().project('id', 'from', 'to', 'label', 'properties').by(__.id()).by(__.select('node').id()).by(__.inV().id()).by(__.label()).by(__.valueMap().by(__.unfold())).fold())`;constnodeLimitQuery=!isNaN(nodeLimit)&&Number(nodeLimit)>0 ? `.limit(${nodeLimit})` : '';consttheQuery=`${query}${nodeLimitQuery}. dedup(). as('node'). project('id', 'label', 'properties', 'edges'). by(__.id()). by(__.label()). by(__.valueMap()). by(__.inE(). project('id', 'from', 'to', 'label', 'properties'). by(__.id()). by(__.outV().id()). by(select('node').id()). by(__.label()). by(__.valueMap()). fold() ) `;returntheQuery;}asyncfunctionexecuteQuery(query){constauthenticator=newGremlin.driver.auth.PlainTextSaslAuthenticator(`/dbs/${config.database}/colls/${config.collection}`,config.primaryKey)constclient=newGremlin.driver.Client(config.endpoint,{
authenticator,traversalsource : "g",rejectUnauthorized : true,mimeType : "application/vnd.gremlin-v2.0+json"});console.log(query);try{constresult=awaitclient.submit(query,{})console.log(JSON.stringify(result,null,2));returnresult;}catch(err){console.error(err);returnnull;}}app.post('/query',async(req,res,next)=>{constnodeLimit=req.body.nodeLimit;letquery=""+req.body.query;letvisualizationNodesAndEdges=[];// Support for sample files to show possible if(query.startsWith("sample:")){try{constsample=query.split(":")[1];visualizationNodesAndEdges=JSON.parse(fs.readFileSync(path.join(__dirname,"samples",`${sample}.json`),'utf8'));}catch(err){console.error(err);}}else{lettheQuery;if(query.endsWith(".out()")){theQuery=makeOutQuery(query,nodeLimit);}elseif(query.endsWith(".in()")){theQuery=makeInQuery(query,nodeLimit);}else{theQuery=makeSelfQuery(query);}constresult=awaitexecuteQuery(theQuery);if(result!==null){visualizationNodesAndEdges=nodesToVisualizationStructure(result._items);}}constvisualizationNodesAndEdgesPrettyfiedJSon=JSON.stringify(visualizationNodesAndEdges,null,2);console.log(visualizationNodesAndEdgesPrettyfiedJSon);res.send(visualizationNodesAndEdgesPrettyfiedJSon);});app.get('/edgecount/:nodeId',async(req,res,next)=>{constnodeId=req.params.nodeId;letquery=`g.V("${nodeId}").project("inEdgesCount", "outEdgesCount").by(__.inE().count()).by(__.outE().count())`;constresult=awaitexecuteQuery(query);// result._items in format: [ { "inEdgesCount": 2, "outEdgesCount": 0 } ]letcountInfo;if(result===null||result._items.length===0){countInfo={'inEdgesCount': -1,'outEdgesCount': -1};// error - node does not exist?}else{countInfo=result._items[0];}res.send(JSON.stringify(countInfo,null,2));});app.listen(config.port,()=>console.log(`Simple Gremlin proxy-server listening on port ${config.port}!`));
I also added support for sample graph visualization files without using a Gremlin server, and no support for drilling through the graph. Create next to the proxy-server.js file a folder samples, and add for example the following file:
modern.json: (patterned after the graph created with TinkerFactory.createModern() as described in the Tinkerpop Reference Documentation
It is the format sent by the proxy-server.js to the front-end:-) I did some additional improvements on the proxy-server.js so other queries are handled correctly as well. I will post an updated version soon.
Did you run it against Cosmos DB, or did it work for other Gremlin servers as well?
Hi @prabushitha, thanks for the great work on the visualizer. I had some issues with Microsoft Cosmos DB, because of the executed query
${query}${nodeLimitQuery}.dedup().as('node').project('id', 'label', 'properties', 'edges').by(__.id()).by(__.label()).by(__.valueMap().by(__.unfold())).by(__.outE().project('id', 'from', 'to', 'label', 'properties').by(__.id()).by(__.select('node').id()).by(__.inV().id()).by(__.label()).by(__.valueMap().by(__.unfold())).fold())
.It contains Gremlin constructs not supported by Cthe Cosmos DB Graph implementation of Gremlin:
by(__.valueMap().by(__.unfold())
.I created a version that works correctly for Cosmos DB Graph where I did split the query into three different queries to get it working correctly. I also added an additional endpoint in the service to request the incoming and outgoing edges. Because Cosmos B Graph contains an authenticated endpoint I configure the proxy server with an included
config.js
file:config.js:
proxy-server.js:
I also added support for sample graph visualization files without using a Gremlin server, and no support for drilling through the graph. Create next to the
proxy-server.js
file a foldersamples
, and add for example the following file:modern.json: (patterned after the graph created with
TinkerFactory.createModern()
as described in the Tinkerpop Reference DocumentationIf instead of a query the following string is specified
sample:modern
the sample JSON is read and returned.The text was updated successfully, but these errors were encountered: