Following is a Node we having in DB
P:Person { name:"xxx", skill:"Java" }
and after awhile, we would like to change the Skill to skill array, is it possible?
P:Person { name:"xxx", skill:["Java", "Javascript"] }
Which Cypher query should I use?
If you have a single skill value in skill, then just do
MATCH (p:Person)
WHERE HAS (p.skill)
SET p.skill=[p.skill]
If there are multiple values you need to convert to an array such as P:Person { name:"xxx", skill:"Java","JavaScript" } then this should work:
MATCH (p:P)
SET p.skill= split(p.skill,",")
In fact, I think your real problem here is not how to get an array property in a node, but how to store it. Your data model is wrong in my opinion, storign data as array in neo4j is not common, since you have relations to store multiple skills (in your example).
How to create your data model
With your question, I can already see that you have one User, and one User can have 1..n skills.
I guess that one day (maybe tomorrow) you will need to know which users are able to use Java, C++, PHP, and every othre skills.
So, Here you can already see that every skill should have its own node.
What is the correct model in this case?
I think that, still with only what you said in question, you should have something like this:
(:Person{name:"Foo"})-[:KNOWS]->(:Skill{name:"Bar"})
using such a data model, you can get every Skill known by a Person using this query:
MATCH (:Person{name:"Foo"})-[:KNOWS]->(skill:Skill)
RETURN skill //or skill.name if you just want the name
and you can also get every Person who knows a Skill using this:
MATCH (:Skill{name:"Bar"})<-[:KNOWS]-(person)
RETURN person //Or person.name if you just want the name
Keep in mind
Storing array values in properties should be the last option when you are using neo4j.
If a property can be found in multiple nodes, having the same value, you can create a node to store it, then you will be able to link it the other nodes using relations, and finding every node having the property X = Y will be easier.
Related
I have a list of Person objects which are related to each other with spouse relation in the order of which they appear in the list.
enum class Gender {
MAN, WOMAN
}
data class Person(val name: String, val age: Int, val gender: Gender)
In the list, each Person with Gender MAN is the spouse of the following Person with WOMAN Gender (and vice versa) and each entry in the list is followed by alternating genders with MAN gender be the first.
The list should ideally be like [MAN, WOMAN, MAN, WOMAN, MAN, WOMAN] (obviously it will be a list of Person objects for simplicity I am putting a list of Gender here) but it could also be like [WOMAN, MAN, WOMAN, MAN, WOMAN, MAN]. In the latter case, the first appearing WOMAN is the spouse of the last appearing MAN.
How this second case could be handled in kotlin by using functional programming.
My current approach involves checking if the first Person has a gender women then i remove the first and last objects in the list and then add them in the end but this is not fully a functional programming solution.
Anyone can guide me about that?
Thanks
What do you mean by fully functional approach?
Similar to what you mentioned, you can fix the order by a simple statement like this:
val correctList = if(list.first().gender == MAN) list else list.drop(1) + list.first()
If you want a more general approach, you can do something like this:
// separate the people into a list of gender=MAN and a list of everyone else
// the result is a Pair, so I'm destructuring that into two variables
val (men, women) = people.partition { it.gender == MAN }
// use zip to take a person from each list and combine them into a list of pairs
men.zip(women)
// use flatMap to turn each pair into a list of two people
// just using map would create a list of lists, flatMap flattens that into
// a single list of people, alternating gender=MAN, gender=WOMAN
.flatMap { it.toList() }
This way it doesn't matter how your original list is ordered, it can start with any element and you can have the different types completely mixed up - BABBAABA will still come out as ABABABAB. So it's a general way to combine mixed data streams - partition separates them into groups, and zip lets you take an element from each group and do something with them.
Here I'm just letting zip create Pairs, and then flatMap turns those back into an ordered list (if that's what you want). You could also do a forEach on each pair instead (say if you wanted to set a value on each Person to link them to each other), or zip can take a transform function too.
Also zip terminates when one of the lists runs out (e.g for AAA and BB you'll get two pairs) so this works for generating complete pairs of elements - if you also needed to handle elements without a "partner" you'd need to do a bit more work
I'm new to Aerospike and am probably missing something fundamental, but I'm trying to see an enumeration of the Keys in a Set (I'm purposefully avoiding the word "list" because it's a datatype).
For example,
To see all the Namespaces, the docs say to use SHOW NAMESPACES
To see all the Sets, we can use SHOW SETS
If I want to see all the unique Keys in a Set ... what command can I use?
It seems like one can use client.scan() ... but that seems like a super heavy way to get just the key (since it fetches all the bin data as well).
Any recommendations are appreciated! As of right now, I'm thinking of inserting (deleting) into (from) a meta-record.
Thank you #pgupta for pointing me in the right direction.
This actually has two parts:
In order to retrieve original keys from the server, one must -- during put() calls -- set policy to save the key value server-side (otherwise, it seems only a digest/hash is stored?).
Here's an example in Python:
aerospike_client.put(key, {'bin': 'value'}, policy={'key': aerospike.POLICY_KEY_SEND})
Then (modified Aerospike's own documentation), you perform a scan and set the policy to not return the bin data. From this, you can extract the keys:
Example:
keys = []
scan = client.scan('namespace', 'set')
scan_opts = { 'concurrent': True, 'nobins': True, 'priority': aerospike.SCAN_PRIORITY_MEDIUM }
for x in (scan.results(policy=scan_opts)): keys.append(x[0][2])
The need to iterate over the result still seems a little clunky to me; I still think that using a 'master-key' Record to store a list of all the other keys will be more performant, in my case -- in this way, I can simply make one get() call to the Aerospike server to retrieve the list.
You can choose not bring the data back by setting includeBinData in ScanPolicy to false.
I have this armor table, that has three fields to identify individual designs: make, model and version.
I have to implement a search feature for our software, that lets a user search armors according to various criteria, among which their design.
Now, the users' idea of a design is a single string that contains make, model and version concatenated, so the entry is that single string. Let's say they want to look up the specifications for make FH, model TT, version 27, they'll think of (and type) "FHTT27".
We use an IQueryOver object, upon which we add successive conditions according to the criteria. For the design, our code is
z_quoQuery = z_quoQuery.And(armor => armor.make + armor.model + armor.version == z_strDesign);
Which raises an InvalidOperationException, "variable 'armor' of type 'IArmor' referenced from scope '', but it is not defined".
This is described as a bug here: https://github.com/mbdavid/LiteDB/issues/637
After a lot of trial and error, it seems that syntaxs that don't use the armor variable first raise that exception.
Obviously, I have to go another route at least for now, but after searching for some time I can't seem to find how. I thought of using something like
z_quoQuery = z_quoQuery.And(armor => armor.make == z_strDesign.SubString(0, 2).
And(armor => armor.model == z_strDesign.SubString(2, 2).
And(armor => armor.version == z_strDesign.SubString(4, 2);
Unfortunately, the fields are liable to have variable lengths. For instance, another set of values for make, model, and version might be, respectively, "NGI", "928", and "RX", that the code above would parse wrong. So I can't bypass the difficulty that way. Nor can I use a RegEx.
Neither can I make up a property in my Armor class that would concatenate all three properties, since it cannot be converted to SQL by NHibernate.
Has someone an idea of how to do it?
Maybe I should use an explicit SQL condition here, but how would it mix with other conditions?
It seems you can use Projections.Concat to solve your issue:
z_quoQuery = z_quoQuery.And(armor => Projections.Concat(armor.make, armor.model, armor.version) == z_strDesign);
I want to check if an entity is part of the users input.
Example:
entities['#PRODUKT_INTENT_STOP_LIST']?.contains($variables.tmpEntity)
As you can see by this example, the value of the entity#PRODUKT_INTENT_STOP_LIST
is a variable. I put this at a condition for a node, but this is not working.
If I use a hardcoded string instead of the variable it is working fine.
entities['#PRODUKT_INTENT_STOP_LIST']?.contains('Chart') works fine
but setting $variables.tmpEntity to 'Chart' a and then ask for
entities['#PRODUKT_INTENT_STOP_LIST']?.contains($variables.tmpEntity)
is not working.
Can someone tells me what's wrong here?
Still trying to understand what you are trying to do.But if you want to check whether an entity exist in your input or not you can do it by applying condition on size of that entity.
"context":{
"size":"<?#Entity.size()?>"
}
now if size is equals to 0 then entity does not exist.
I know this is a longer way but it also tells you how many times does that entity exist in your input.
Hi I used the wrong statement.
This statement should work:
entities[PRODUKT_INTENT_STOP_LIST]?.get($variables.countEntity).value==$variables.$variables.tmpEntity
$variables.countEntity : counter to iterate thru entity array #PRODUKT_INTENT_STOP_LIST to check if an entity value is equal $variables.tmpEntity
Regards
Suppose I have a Model Class named Anything, in Yii, and all I want is to get not the field value, but the field name, how could I do that?
Because using something like:
$anything = new Anything;
$anything->field_name;
Returns the value of that field, which is the purpose for that, still, if all you want is the string of the name of the field, how could you do that?
I tried using:
$anything->attributes;
But it just returns an array of field names, I want to try and get a specific value as a defined constant.
What I want to do is use the $_POST with specific and practical use, so I wouldn't need to use:
$_POST["Model_name"];
Instead I could use:
$_POST[Anything::model()->name][Anything::model()->field_name->name]
Which seems a lot better than "" and '' here and there. Mostly because I'm trying to set multiple fieldsets of different Models in the same formulary.
So if I could use:
$_POST[Anything::model()->name][Anything::model()->field_name->name];
and
$_POST[Something::model()->name][Something::model()->field_name->name]
and
$_POST[Godspeed::model()->name][Godspeed::model()->field_name->name]
It would save a lot of problems I might had in the future.
$strModelName = 'ModelName'; //dynamic - whatever model name you put in it
$find_id = 3;
$record = $strModelName::model()->findByPK($find_id); //it's same with ModelName::model()->findByPK(3)
foreach($record->attributes as $key=>$value){
var_dump($_POST[$strModelName][$key]); //get value corresponding to given key
}
Btw, you still need check whether the model is exist or not
http://www.yiiframework.com/forum/index.php/topic/22790-check-if-model-exists/