How to refine the mandatory property of nodes from a grouping in YANG language? - model-driven

I defined a grouping which has a leaf with mandatory property set to false.
But in some cases, I would like to use this grouping and specify that the leaf should be mandatory. How do I achieve this in YANG?

You would use the refine statement when specifying a use of your grouping.
module mandatory-and-grouping {
namespace "org:example:mandatory-and-grouping";
prefix "mag";
grouping my-grouping {
leaf my-leaf {
type string;
}
}
container top {
uses my-grouping {
refine my-leaf {
mandatory true;
}
}
}
}
7.13.2. The "refine" Statement
Some of the properties of each node in the grouping can be refined
with the "refine" statement. The argument is a string that
identifies a node in the grouping. This node is called the refine's
target node. If a node in the grouping is not present as a target
node of a "refine" statement, it is not refined and thus is used
exactly as it was defined in the grouping.
The argument string is a descendant schema node identifier (see
Section 6.5).
The following refinements can be done:
A leaf or choice node may get a default value, or a new default
value if it already had one.
A leaf-list node may get a set of default values, or a new set of
default values if it already had defaults; i.e., the set of
refined default values replaces the defaults already given.
Any node may get a specialized "description" string.
Any node may get a specialized "reference" string.
Any node may get a different "config" statement.
A leaf, anydata, anyxml, or choice node may get a different
"mandatory" statement.
A container node may get a "presence" statement.
A leaf, leaf-list, list, container, anydata, or anyxml node may
get additional "must" expressions.
A leaf-list or list node may get a different "min-elements" or
"max-elements" statement.
A leaf, leaf-list, list, container, choice, case, anydata, or
anyxml node may get additional "if-feature" expressions.
Any node can get refined extensions, if the extension allows
refinement. See Section 7.19 for details.
RFC7950, Section 7.13.2

Related

How to define Enum Type Neo4j?

I have a node:
Database: {
name: 'example',
description: 'this is the example database'
type: 'relational'
}
I want type to be an enum like:
DB_TYPE enum {
relational
document
graph
other
}
1st Question: How can I define this enum type so that all "database" nodes can have a type property that is one of these 4 values?
Should I just leave it as a string and forget about making an enum?
I considered using labels for these nodes like: :Relational, :Document.
2nd Question: If I should use labels, what is the cypher syntax to determine if a given database node is either relational, document, graph, or other?
AFAIK, there is no way to define an enum property for a node. From what you described, I think you'd better use labels. If your really don't want to use labels, another alternative could be having one node per type and then connecting database nodes to these type nodes. But depending on the size of your graph, those type nodes could become super nodes with lots of relationships. I would not suggest this approach. Again to me the best solution in such usecases is to use labels.
The easiest would be checking labels against labels(a) where a is your node. For example:
MATCH (a) where 'Relational' in labels(a) OR 'Document' in labels(a) ....
There is also an APOC procedure apoc.label.exists that you can use:
MATCH (a) where apoc.label.exists(a, 'Relational') OR apoc.label.exists(a, 'Document')....
If you are using Python with neomodel as an ORM tool, you can define your model in the following way:
from neomodel import StructuredNode, StringProperty
class Database(StructuredNode):
TYPES = (
('RELATIONAL', 'relational'),
('DOCUMENT', 'document'), # ...
)
name = StringProperty(unique_index=True),
description = StringProperty(),
type = StringProperty(choices=TYPES)
More info:
https://neomodel.readthedocs.io/en/latest/module_documentation.html#neomodel.properties.StringProperty
https://github.com/neo4j-contrib/neomodel/commit/dee7ca0b83cecf0156dc164052701ce7b8ebe14a

Add Integer Number to existing Values - Neo4j

Using Neo4j.
I would like to add a integer number to values already existing in properties of several relationships that I call this way:
MATCH x=(()-[y]->(s:SOL{PRB:"Taking time"})) SET y.points=+2
But it doesn't add anything, just replace by 2 the value I want to incremente.
To achieve this use
SET y.points = y.points + 2
From your original question it looks like you were trying to use the Addition Assignment operator which exists in lots of languages (e.g. python, type/javascript, C#, etc.). However, in cypher += is a little different and is designed to do this in a way which allows you to add or update properties to or on entire nodes or relationships based on a mapping.
If you had a parameter like the below (copy this into the neo4j browser to create a param).
:param someMapping: {a:1, b:2}
The query below would create a property b on the node with value 2, and set the value of property a on that node to 1.
MATCH (n:SomeLabel) WHERE n.a = 0
SET n+= $someMapping
RETURN n

How to set all relationships of a certain type -- replacing the old ones if necessary -- in Neo4j?

I have a node id for an event, and list of node ids for users that are hosting the event. I want to update these (:USER)-[:HOSTS]->(:EVENT) relationships. I dont just want to add the new ones, I want to remove the old ones as well.
NOTE: this is coffeescript syntax where #{} is string interpolation, and str() will escape any characters for me.
Right now I'm querying all the hosts:
MATCH (u:USER)-[:HOSTS]->(:EVENT {id:#{str(eventId)}})
RETURN u.id
Then I'm determining which hosts are new and need to be added and which ones are old and need to be removed. For the old ones, I remove them
MATCH (:HOST {id:#{str(host.id)}})-[h:HOSTS]->(:EVENT {id:#{str(eventId)}})
DELETE h
And for the new ones, I add them:
MATCH (e:EVENT {id: #{str(eventId)}})
MERGE (u:USER {id:#{str(id)}})
SET u.name =#{str(name)}
MERGE (u)-[:HOSTS]->(e)
So my question is, can I do this more efficiently all in one query? I want want to set the new relationships, getting rid of any previous relationships that arent in the new set.
If I understand your question correctly, you can achieve your objective in a single query by introducing WITH and FOREACH. On a sample graph created by
CREATE (_1:User { name:"Peter" }),(_2:User { name:"Paul" }),(_3:User { name:"Mary" })
CREATE (_4:Event { name:"End of the world" })
CREATE _1-[:HOSTS]->_4, _2-[:HOSTS]->_4
you can remove the no longer relevant hosts, and add the new hosts, as such
WITH ["Peter", "Mary"] AS hosts, "End of the world" AS eventId
MATCH (event:Event { name:eventId })<-[r:HOSTS]-(u:User)
WHERE NOT u.name IN hosts
DELETE r
WITH COLLECT(u.name) AS oldHosts, hosts, event
WITH FILTER(h IN hosts
WHERE NOT h IN oldHosts) AS newHosts, event, oldHosts
FOREACH (n IN newHosts |
MERGE (nh:User { name:n })
MERGE nh-[:HOSTS]->event
)
I have made some assumptions, at least including
The new host (:User) of the event may already exists, therefore MERGE (nh:User { name:n }) and not CREATE.
The old [:HOSTS]s should be disconnected from the event, but not removed from the database.
Your coffee script stuff can be translated into parameters, and you can translate my pseudo-parameters into parameters. In my sample query I simulate parameters with the first line, but you may need to adapt the syntax according to how you actually pass the parameters to the query (I can't turn Coffee into Cypher).
Click here to test the query. Change the contents of the hosts array to ["Peter", "Paul"], or to ["Peter", "Dragon"], or whatever value makes sense to you, and rerun the query to see how it works. I've used name rather than id to catch the nodes, and again, I've simulated parameters, but you might be able to translate the query to the context from which you want to execute it.
Edit:
Re comment, if you want the query to also match events that don't have any hosts you need to make the -[:HOSTS]- part of the pattern optional. Do so by braking the MATCH clause in two:
MATCH (event:Event { name:eventId })
OPTIONAL MATCH event<-[r:HOSTS]-(u:User)
The rest of the query is the same.

Node identifiers in neo4j

I'm new to Neo4j - just started playing with it yesterday evening.
I've notice all nodes are identified by an auto-incremented integer that is generated during node creation - is this always the case?
My dataset has natural string keys so I'd like to avoid having to map between the Neo4j assigned ids and my own. Is it possible to use string identifiers instead?
Think of the node-id as an implementation detail (like the rowid of relational databases, can be used to identify nodes but should not be relied on to be never reused).
You would add your natural keys as properties to the node and then index your nodes with the natural key (or enable auto-indexing for them).
E..g in the Java API:
Index<Node> idIndex = db.index().forNodes("identifiers");
Node n = db.createNode();
n.setProperty("id", "my-natural-key");
idIndex.add(n, "id",n.getProperty("id"));
// later
Node n = idIndex.get("id","my-natural-key").getSingle(); // node or null
With auto-indexer you would enable auto-indexing for your "id" field.
// via configuration
GraphDatabaseService db = new EmbeddedGraphDatabase("path/to/db",
MapUtils.stringMap(
Config.NODE_KEYS_INDEXABLE, "id", Config.NODE_AUTO_INDEXING, "true" ));
// programmatic (not persistent)
db.index().getNodeAutoIndexer().startAutoIndexingProperty( "id" );
// Nodes with property "id" will be automatically indexed at tx-commit
Node n = db.createNode();
n.setProperty("id", "my-natural-key");
// Usage
ReadableIndex<Node> autoIndex = db.index().getNodeAutoIndexer().getAutoIndex();
Node n = autoIndex.get("id","my-natural-key").getSingle();
See: http://docs.neo4j.org/chunked/milestone/auto-indexing.html
And: http://docs.neo4j.org/chunked/milestone/indexing.html
This should help:
Create the index to back automatic indexing during batch import We
know that if auto indexing is enabled in neo4j.properties, each node
that is created will be added to an index named node_auto_index. Now,
here’s the cool bit. If we add the original manual index (at the time
of batch import) and name it as node_auto_index and enable auto
indexing in neo4j, then the batch-inserted nodes will appear as if
auto-indexed. And from there on each time you create a node, the node
will get indexed as well.**
Source : Identifying nodes with Custom Keys
According Neo docs there should be automatic indexes in place
http://neo4j.com/docs/stable/query-schema-index.html
but there's still a lot of limitations
Beyond all answers still neo4j creates its own ids to work faster and serve better. Please make sure internal system does not conflict between ids then it will create nodes with same properties and shows in the system as empty nodes.
the ID's generated are default and cant be modified by users. user can use your string identifiers as a property for that node.

How do i check if a node is a child of another node?

I want to get all "generateId" values of the text nodes which are a child of a specific node whose attribute "id" value is known. I can i test for this condition using XSL?
Use an XPath 2.0 expression like this:
//specificNode[#id=$knownValue]/text()/generate-id(.)
You may also use keys (<xsl:key> and the key() function) for more efficient selection of all specificNode-s that have an id attribute with a knownValue.

Resources