Chapter 12 · APOC, Procedures, Functions, Triggers-Like Workflows, and Extending Cypher

Collections, Maps, Text, Date, Conversion, Path Expansion, and Utility Procedures

Compare native Cypher with selected APOC Core collection, map, text and path helpers, keeping row cardinality and deprecation risk observable.

Advanced150–190 minutesUtility equivalence + bounded path labNeo4j 2026.07.1 Community · Cypher 25APOC Core 2026.07.1 optionalLast reviewed: September 2026

Learning outcomes

AtlasMart receives product attributes in inconsistent maps and needs a bounded “related supply-chain entities” view. Both requirements can be solved several ways. The engineering question is not whether APOC has a function for them; it is whether APOC adds expressive value without hiding cardinality, compatibility or maintenance costs.

01

Compare native Cypher collection/map/text/date expressions with APOC Core equivalents.

02

Use APOC functions inside row expressions and procedures through CALL/YIELD without confusing their cardinality.

03

Apply apoc.path.expandConfig with explicit bounds and filters.

04

Recognize APOC utilities deprecated in Cypher 25 when native language features supersede them.

05

Document why a chosen helper is less coupled or more testable than its alternatives.

Chapter 12 baseline · reviewed 9 September 2026

The mandatory lab continues Neo4j Community 2026.07.1, database neo4j, explicit CYPHER 25 for version-sensitive examples, container atlasmart-neo4j, authentication enabled, loopback HTTP/Bolt endpoints, and the AtlasMart identifiers/model built in Chapters 01–11. Neo4j 5.26.30 remains the LTS comparison line. This chapter adds APOC Core 2026.07.1 as an optional extension; APOC Extended is never required.

Evidence and privilege note

This generation environment does not run the Neo4j container, so no plugin load, procedure list, filesystem read/write, HTTP request, trigger execution or custom-JAR output is invented. The lab tells you exactly what to inspect. Community Edition lacks Enterprise RBAC/load privileges, so the free path emphasizes configuration minimization, loopback-only access, file/network denial by default, and application-level authorization boundaries.

1. Prefer the language first; use APOC for a capability gap

Requirement Pure Cypher first APOC Core candidate Decision
Deduplicate list UNWIND + DISTINCT + collect apoc.coll.toSet() when its ordering contract is acceptable Cypher is explicit; APOC can be concise
Merge two maps Map projection / explicit keys apoc.map.merge() APOC is useful for truly dynamic maps
Normalize product search key Native string functions/regex where sufficient apoc.text.clean() Choose based on exact normalization contract
Date/time arithmetic Native date()/datetime()/duration() Some legacy APOC date helpers Prefer native temporal types in new Cypher 25 work
Fine-grained path expansion Quantified path patterns + predicates apoc.path.expandConfig() APOC when configurable relationship/label filters or uniqueness modes materially simplify the traversal

APOC 2025.07+ evolves for Cypher 25. Some older conveniences are deprecated as Cypher gains equivalent language features. A stable codebase treats deprecation reports as migration input rather than freezing historical recipes.

2. Functions preserve the row; procedures can multiply it

Cypher · function expressions
CYPHER 25WITH ['Cameras','Store IoT','Cameras'] AS raw,     {source:'erp', priority:1} AS leftMap,     {priority:2, verified:true} AS rightMapRETURN apoc.coll.toSet(raw) AS uniqueCategories,       apoc.map.merge(leftMap,rightMap) AS merged,       apoc.text.clean(' Trail-Camera 1001 ') AS normalized;

A function produces a value in the current row. By contrast, a path procedure can emit many rows per input node, so its cardinality belongs in the query design.

Cypher · procedure emits paths
CYPHER 25MATCH (s:Supplier {supplierId:'SUP-1001'})CALL apoc.path.expandConfig(s, {  relationshipFilter:'SUPPLIES>|SUPPLIED_BY<|IN_CATEGORY>|STOCKED_AT>',  minLevel:1,  maxLevel:3,  bfs:true,  uniqueness:'RELATIONSHIP_PATH',  limit:25}) YIELD pathRETURN length(path) AS hops,       [n IN nodes(path) | coalesce(n.productId,n.categoryId,n.storeId,n.supplierId)] AS idsORDER BY hops, ids;
Bound the traversal

apoc.path.expandConfig can be more configurable than a plain pattern, but it does not abolish graph fan-out. maxLevel, relationship/label filters, uniqueness mode and result limits are correctness/performance inputs—not afterthoughts.

3. Same result, three implementation locations

Cypher · pure map shaping
CYPHER 25MATCH (p:Product {productId:$id})RETURN p{.productId,.name,.category,.price,         displayName: toUpper(p.name)} AS product;
Cypher · APOC dynamic map merge
CYPHER 25MATCH (p:Product {productId:$id})WITH p, p{.productId,.name,.category,.price} AS baseRETURN apoc.map.merge(base,{displayName:toUpper(p.name)}) AS product;
Python · application shaping
record = session.run(    "MATCH (p:Product {productId:$id}) RETURN p{.*} AS product",    id="P-1001",).single()product = dict(record["product"])product["displayName"] = product["name"].upper()

All three can be correct. Native Cypher keeps logic near the query and avoids plugin coupling; APOC is useful for dynamic server-side transformations; application code can be easier to unit-test and keeps presentation logic out of the database. Measure payload size and round trips before assuming one is faster.

4. Edge cases that change the answer

Edge case Failure if ignored Repair
List contains null Predicate/function behavior can propagate null unexpectedly Specify null filtering before deduplication/transformation
Dynamic map overwrites stable ID Merge precedence silently changes identity field Keep identity outside mutable overlay or assert key set
Text normalization is locale/domain-sensitive “Clean” may collapse distinct business values Define canonicalization contract in application/domain tests
Path includes cycles/high-degree hubs Result rows/memory grow sharply Bound depth, filter relationship types/labels and test dense cases
APOC helper deprecated in Cypher 25 Upgrade emits warnings or future removal risk Use current native replacement and regression-test result equivalence

5. Deliberately wrong: APOC path expansion as a universal shortest path engine

apoc.path.expandConfig controls traversal expansion; it is not automatically equivalent to Cypher shortest selectors or a weighted graph algorithm. If AtlasMart asks for minimum freight cost, a “first path returned by BFS” is not a weighted shortest-path guarantee. Choose transactional Cypher for bounded pattern questions and GDS/application algorithms for algorithmic weighted routing.

6. Lab: compare outputs, not syntax length

Cypher · ensure fixture
CYPHER 25MERGE (c:Customer {customerId:'C-1001'})SET c.name='Mina Rahimi'MERGE (p1:Product {productId:'P-1001'})SET p1.name='Trail Camera', p1.category='Cameras', p1.price=129.90MERGE (p2:Product {productId:'P-2001'})SET p2.name='Smart Shelf Sensor', p2.category='Store IoT', p2.price=79.50MERGE (o:Order {orderId:'O-5001'})SET o.status='PAID', o.orderedAt=datetime('2026-09-08T16:30:00Z')MERGE (c)-[:PLACED]->(o)MERGE (o)-[:CONTAINS {quantity:1}]->(p1)MERGE (o)-[:CONTAINS {quantity:2}]->(p2);
Cypher · inspect selected utilities
CYPHER 25CALL apoc.help('map.merge') YIELD name,type,text RETURN name,type,text;CALL apoc.help('path.expandConfig') YIELD name,type,text RETURN name,type,text;SHOW FUNCTIONS YIELD nameWHERE name IN ['apoc.map.merge','apoc.text.clean','apoc.coll.toSet']RETURN name ORDER BY name;SHOW PROCEDURES YIELD nameWHERE name='apoc.path.expandConfig'RETURN name;

Verification checklist: record whether each helper exists in your exact Core build; run the pure Cypher and APOC variants on the same fixture; compare rows and values; then inspect plan/cardinality separately rather than inferring performance from shorter query text.

7. Production judgment

Every utility moved into the server JVM inherits the server upgrade, memory and security lifecycle. A two-line APOC helper is justified when it makes a stable, well-tested requirement clearer or avoids expensive client round trips. It is not justified merely because it is shorter than native Cypher.

Check your understanding

  1. What cardinality difference separates an APOC function from a path procedure?
  2. Why prefer native temporal functions for new Cypher 25 work?
  3. Does limit alone make a path expansion cheap?
  4. Why test dense graph fixtures?
  5. What evidence should justify an APOC utility?
Review the answers

1. A function returns a value within the current row; a procedure can emit zero or many rows through CALL/YIELD.

2. They are part of the language contract and reduce plugin/deprecation coupling.

3. No. Work can still expand before limiting; selective anchors, bounds and filters remain important.

4. Low-degree examples can hide combinatorial row growth and memory/latency problems.

5. Equivalent-result tests plus a clear maintainability, expressiveness, round-trip or measured performance benefit.

Summary and next step

APOC Core is most useful when it fills a specific language/tooling gap. Lesson 3 raises the risk level by crossing file and network boundaries for JSON integration and export.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.