bornytm
bornytm

Reputation: 813

returning an object from collect (cypher/neo4j)

I'm trying to return content in the language specified by the user, or the default language (english) if the content is not found in the selected language. It seems like returning an object from a collect statement is not supported. Is there a way to achieve a similar result though?

The query as it is now:

MATCH (meta:contentMeta)<-[metaLang:HAS_META]-(content:content)-[:TAGGED_WITH]-(termNode:term)-[lang:HAS_LANGUAGE]-(langNode:termMeta)
WHERE 
    metaLang.languageCode = {language} 
    OR metaLang.languageCode = {defaultLanguage} 
    AND lang.languageCode = {language} 
    OR lang.languageCode = {defaultLanguage}
RETURN DISTINCT collect(langNode.name) AS terms, 
    content.displayType AS displayType, 
    content.savedAs AS savedAs, 
    content.webURL AS webURL, 
    content.embedSrc AS embedsrc, 
    content.UUID AS UUID
LIMIT 15

The problem is what I really want returned is an object with the name of the node as well as the language code. Something like:

collect(langNode.name, langNode.languageCode) AS terms

or this:

collect(langNode.name) AS terms.name, 
collect(langNode.languageCode) AS terms.languageCode

Of course, this syntax does not work. Are there any simple solutions to this?

Upvotes: 2

Views: 2238

Answers (2)

cybersam
cybersam

Reputation: 67044

I am not sure either how your model works, but I see some possible errors and opportunities for optimization.

In my suggested Cypher query below, I have added a couple of arrows in the 1st line, to indicate what I presume are correct relationship directionalities -- this can speed up things. I also removed unneeded variable names.

In addition, it is not clear if your current BOOLEAN tests will (always) work as intended, as the neo4j manual does not document the operator precedence between OR and AND operators. So, I have simplified the BOOLEAN tests and made sure that they will (always) work as intended, using the 'IN' operator.

Finally, I did not think you needed collect(), since it may be that each term has only one language.

MATCH (:contentMeta)<-[metaLang:HAS_META]-(content:content)<-[:TAGGED_WITH]-(:term)-[lang:HAS_LANGUAGE]->(langNode:termMeta)
WHERE metaLang.languageCode IN [{language}, {defaultLanguage}] AND lang.languageCode IN [{language}, {defaultLanguage}]
RETURN DISTINCT {name:langNode.name, languageCode:langNode.languageCode} AS terms, 
    content.displayType AS displayType, 
    content.savedAs AS savedAs, 
    content.webURL AS webURL, 
    content.embedSrc AS embedsrc, 
    content.UUID AS UUID
LIMIT 15

Upvotes: 4

jjaderberg
jjaderberg

Reputation: 9952

Not sure I understand exactly how your model works, but you could probably achieve what you want with map and collection literals. For your first example you could experiment with

collect ( [langNode.name, langNode.languageCode] ) as terms

and second example

{name:collect (langNode.name), languageCode:collect (langNode.languageCode) } as terms

or

collect ( {name:langNode.name, languageCode:langNode.languageCode} ) as terms

Upvotes: 6

Related Questions