Use of MERGE to insert patterns of nodes and edges - merge

I'm trying to insert patterns (nodes and edges) using merge. Using the demo movies graph, I'm sending the following cypher query: the movie exists, I'd like to create the User node and the edge in one query.
MERGE (top:Movie { title:'Top Gun' })<-[:viewed]-(user:User {Name:'Pierre'})
ON CREATE SET user.created = timestamp()
ON MATCH SET user.lastSeen = timestamp()
RETURN user,top;
"MERGE needs at least some part of the pattern to already be known. Please provide values for one of: user, top"
Actually, top exits, I can't figure out what's wrong in my query. Thanks for your help.
Pierre

Would this work?
MATCH (top:Movie { title:'Top Gun' })
MERGE (top)<-[:viewed]-(user:User {Name:'Pierre'})
ON CREATE SET user.created = timestamp()
ON MATCH SET user.lastSeen = timestamp()
RETURN user,top;
or this for creates:
MERGE (top:Movie { title:'Top Gun' })
MERGE (user:User {Name:'Pierre'})
ON CREATE SET user.created = timestamp()
ON MATCH SET user.lastSeen = timestamp()
MERGE (top)<-[:viewed]-(user)
RETURN user,top;

Related

Getting ElasticSearch document fields inside of loaded records in searchkick

Is it possible to get ElasticSearch document fields inside of loaded AR records?
Here is a gist that illustrates what I mean: https://gist.github.com/allomov/39c30905e94c646fb11637b45f43445d
In this case I want to avoid additional computation of total_price after getting response from ES. The solution that I currently see is to include the relationship and run total_price computation for each record, which is not so optimal way to perform this operation, as I see it.
result = Product.search("test", includes: :product_components).response
products_with_total_prices = result.map do |product|
{
product: product
total_price: product.product_components.map(&:price).compact.sum
}
end
Could you please tell if it is possible to mix ES document fields into AR loaded record?
As far as I'm aware it isn't possible to get a response that merges the document fields into the loaded record.
Usually I prefer to completely rely on the data in the indexed document where possible (using load: false as a search option), and only load the AR record(s) as a second step if necessary. For example:
result = Product.search("test", load: false).response
# If you also need AR records, could do something like:
product_ids = result.map(&:id)
products_by_id = {}
Product.where(id: product_ids).find_each do |ar_product|
products_by_id[ar_product.id] = ar_product
end
merged_result = result.map do |es_product|
es_product[:ar_product] = products_by_id[es_product.id]}
end
Additionally, it may be helpful to retrieve the document stored in the ES index for a specific record, which I would normally do by defining the following method in your Product class:
def es_document
return nil unless doc = Product.search_index.retrieve(self).presence
Hashie::Mash.new doc
end
You can use select: true and the with_hit method to get the record and the search document together. For your example:
result = Product.search("test", select: true)
products_with_total_prices =
result.with_hit.map do |product, hit|
{
product: product,
total_price: hit["_source"]["total_price"]
}
end

MATCH command, using $currentMatch in WHILE to stop traversal

I want to traverse a graph using match, but stop the traversal when a certain node is not connected to another specific node.
To clarify, I have the following setup:
Setup of graph
My goal is to perform the following query:
For a wall, give me all linked/deep properties of that wall that are part of the same commit as the wall, but only if the full path from property to wall is part of commit
This means that, starting from commit #21:0, I go to wall #30:0, for which I should get 0 properties (note that property #34:0 is not linked to commit #21:0!), while starting from commit #22:0, would go to wall #29:0, for which I should get all 4 properties. Basically I want to stop the traversal of the MATCH whenever a node is hit which is not connected to the specified commit node.
I tried a MATCH command, with a while in which I check if there is a shortestPath from the commit to the $currentMatch. However, this doesn't seem to work, I get error that Vertex ID cannot be NULL.
My query is like:
select expand(ret) from (
MATCH {class: V, as: commit, where:(#rid = #21:0)},
{as: commit}.out("commitlink"){as: wall, where:(#class INSTANCEOF "Wall")},
{as: wall}.out("E"){as: props, where:(#class = "Property"), while:(shortestPath($matched.commit, $currentMatch, "OUT","commitlink").size() > 0)}
return items as ret)
... but note that this query gives a the "Vertex id can not be null" error.
I seem to misunderstand the availability of $currentMatch in the while part of the command.
EDIT:
This seems to do the job:
select expand($properties) LET
$commit = (SELECT FROM #22:0),
$wall = (SELECT FROM (SELECT expand(out("commitlink")) FROM $commit) WHERE
#class INSTANCEOF "Wall"),
$properties = (SELECT FROM (TRAVERSE OUT("E") FROM $wall WHILE (shortestPath($commit, #rid, "OUT", "commitlink").size() > 0)) WHERE #class INSTANCEOF "Property")
But is there a drawback in using traverse queries instead of MATCH?
I don't know if I get what you want but what I understood is that your query should return all the property that are directly connected to the commit vertex without a Wall in between, am I right?
If this is what you want, try this:
MATCH {class: Property, as: props}.in("commitlink"){as: commit, where:(#rid = #19:0)} return props
this is my schema:
this is the result:
Hoope it helps
Regards

Doing subqueries in Mybatis, or query recursively the selected values

UPDATE:
I understood that the solution to my problem is doing subqueries, which apply a different filter each time, and they have a reduced result set. But I can't find a way to do that in MyBatis logic. Here is my query code
List<IstanzaMetadato> res = null;
SqlSession sqlSession = ConnectionFactory.getSqlSessionFactory().openSession(true);
try {
IstanzaMetadatoMapper mapper = sqlSession.getMapper(IstanzaMetadatoMapper.class);
IstanzaMetadatoExample example = new IstanzaMetadatoExample();
Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, String> entry = it.next();
example.createCriteria().andIdMetadatoEqualTo(entry.getKey()).andValoreEqualTo(entry.getValue());
}
example.setDistinct(true);
res = mapper.selectByExample(example);
I need to execute a new selectByExample but inside the while cycle, and it has to query the previus "SELECTED" results....
Is there a Solution ?
ORIGINAL QUESTION:
I have this table structure
I have to select rows from the table with different filters, specified by the final user.
Those filters are specified by a couple (id_metadato, valore), in example you can have id_metadato = 3 and valore = "pippo";
the user can specify 0-n filters from the web page typing 0-n values inside the search boxes which are based on id_metadato
Obviusly, the more filters the users specifies, the more restriction would have the final query.
In example if the user fills only the first search box, the query will have only a filter and would provide all the rows that will have the couple (id_metadato, valore) specified by the user.
If he uses two search boxes, than the query will have 2 filters, and it will provide all the rows that verify the first condition AND the second one, after the "first subquery" is done.
I need to do this dinamically, and in the best efficient way. I can't simply add AND clause to my query, they have to filter and reduce the result set every time.
I can't do 0-n subqueries (Select * from ... IN (select * from ....) ) efficiently.
Is there a more elegant way to do that ? I'm reading dynamic SQL queries tutorials with MyBatis, but I'm not sure that is the correct way. I'm still trying to figure out the logic of the resosultio, then I will try to implement with MyBatis.
Thanks for the answers
MyBatis simplified a lot this process of nesting subqueries, it was sufficient to concatenate the filter criterias and to add
the excerpt of the code is the following
try {
IstanzaMetadatoMapper mapper = sqlSession.getMapper(IstanzaMetadatoMapper.class);
IstanzaMetadatoExample example = new IstanzaMetadatoExample();
Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, String> entry = it.next();
if (listaIdUd.isEmpty()) {
example.createCriteria().andIdMetadatoEqualTo(entry.getKey()).andValoreEqualTo(entry.getValue());
example.setDistinct(true);
listaIdUd = mapper.selectDynamicNested(example);
continue;
}
example.clear();
example.createCriteria().andIdMetadatoEqualTo(entry.getKey()).andValoreEqualTo(entry.getValue()).andIdUdIn(listaIdUd);
example.setDistinct(true);
listaIdUd = mapper.selectDynamicNested(example);
}

How to concat two columns for search with feathers-sequelize?

I need to search for users by name, their first name and last names are stored in separate columns in a postgresql database. The columns need to be concatenated for search to work properly. Typing the full first and last name of a user should match a result.
What could I pass as a query to the find method of a Feathers service that would allow me to do this?
As in the answer linked you can pass the where clause to the Feathers service by modifying params.query in a before hook:
app.service('users').before({
find(hook) {
const where = Sequelize.where(Sequelize.fn("concat",
Sequelize.col("firstname"),
Sequelize.col("lastname")), {
like: '%John Do%'
}
);
hook.params.query.where = where;
}
})

NumericRangeQuery in NHibernate.Search

I am creating a search, where the user can both choose an interval and search on a term in the same go.
This is however giving me trouble, since I have up until have only used the usual text query.
I am wondering how I am to go about using both a NumericRangeQuery and a regular term query. Usually I would use a query below:
var parser = new MultiFieldQueryParser(
new[] { "FromPrice", "ToPrice", "Description"}, new SimpleAnalyzer());
Query query = parser.Parse(searchQuery.ToString());
IFullTextSession session = Search.CreateFullTextSession(this.Session);
IQuery fullTextQuery = session.CreateFullTextQuery(query, new[] { typeof(MyObject) });
IList<MyObject> results = fullTextQuery.List<MyObject>();
But if I was to e.g. search the range FromPrice <-> ToPrice and also the description, how should I do this, since session.CreateFullTextQuery only takes one Query object?
you can create a single query that is a BooleanQuery combining all the conditions you want to be met.
For the ranges, heres a link to the synthax using the QueryParser:
http://lucene.apache.org/core/old_versioned_docs/versions/2_9_2/queryparsersyntax.html#Range Searches