在 Neo4j 中将对象存储为属性
Posted
技术标签:
【中文标题】在 Neo4j 中将对象存储为属性【英文标题】:Storing object as property in Neo4j 【发布时间】:2015-05-12 20:41:38 【问题描述】:我需要在 Tile 节点内存储一组用户对象。每个用户对象包含三个原始属性; Id(单个字母字符串)、fName 和 lName。这个对象列表是 Tile 节点的一个属性,具有其他几个原始属性。整个 Tile 节点需要序列化为 Json,包括嵌套的 User 对象。
我了解 Neo 无法将复杂对象存储为属性。我将用户创建为具有 id、fName 和 lName 作为属性的单独节点,我可以通过 Cypher 获取这些返回。我还可以获得父 Tile 节点的 Json 输出结果。 (在这种情况下,Users 只是一串以逗号分隔的字母)。但是如何让用户节点输出嵌套在父节点内?
我通过 Cypher 查询将用户对象与 Tile 节点中的用户 ID 字符串关联起来,创建了一个用户对象列表 (userList)。我只需要从两个单独的 json 输出到单个嵌套输出。
我希望这是足够的细节。我正在使用 Neo4j 2.1.6 和 Neo4jClient。我也在使用.Net 4.0。
【问题讨论】:
【参考方案1】:你可以用 cypher 做这样的事情,让 cypher 返回一个复合对象。
MATCH (t:Tile)-[:CONTAINS_USER]-(u:User)
WHERE t.name =~ 'Tile.*'
WITH name: t.name, users: collect(u) AS tile
RETURN collect(tile) AS tiles
【讨论】:
哦,那是作弊。我喜欢。 :) 我要添加什么来显示集合的结果? 有两个集合:1) 查询的第一部分只匹配图块并创建关联用户的集合。这将作为复合tile
地图返回,其中包含一些图块数据和该图块的用户集合。 2) 只是获取所有新的瓦片地图并将它们作为一个集合返回。
哈!现在我懂了!我对此进行了测试并理解了此解决方案。我也更清楚地了解如何使用关系。这很有帮助。【参考方案2】:
您不应将另一个对象存储为嵌套属性。正如您正确指出的那样,neo4j 不支持,但即使支持,您也不应该这样做,因为您应该将两者与关系联系起来。这是 neo4j 等图形数据库的关键优势,因此您应该发挥这种优势并利用关系。
服务器有一个默认的 JSON 格式,倾向于将节点输出为它们自己的 JSON 对象。这意味着实际上,由于您要将其建模为具有关系的两个独立节点,因此默认情况下您无法让服务器将 JSON 嵌套在另一个对象之下。它不会以这种方式嵌套 JSON,因为这不是存储数据的方式。
在这种情况下,我将使用 REST 服务单独获取每个对象的 JSON,然后在您的代码中自己进行嵌套——您的代码是您知道它应该是哪个属性的唯一地方嵌套在下面,以及应该如何完成。
【讨论】:
我同意你应该考虑是否将对象存储为嵌套属性,但说你不能这样做是不正确的,我也认为它也是广义地说,您不应该将任何对象存储为嵌套属性。一个例子是日期,我们可以使用DateTime
,但您也可以将其分解为日、月和年的 3 个连接节点,这可能是合适的,也可能是大材小用。
我最终做的是序列化用户对象列表,并将其作为字符串放入 Tile 节点上的用户属性中。请求 Tile 节点输出有效的嵌套 JSON,所以我认为我走在正确的轨道上。我还有其他一些错误,所以很难确定这是否有效。这可以作为一种策略接受吗?你的两个答案都很棒,一起更强大 - 很好的团队合作!
@ChrisSkardon 点;当然,对于任何技术,您基本上无法做到的事情很少。我理解你所说的 DateTime 的意思,但这是一种特殊情况,通常被认为是内置的原始类型,而不是复杂的用户定义类型。我在考虑复杂的域/用户定义类型,如“银行账户”。 可以吗?嗯,是的...当然,但很难想象 common 场景会是更好的决定。 (当然你也可以想出不常见的利基,它可能更可取)
@WayneCordrey 我认为 Dave Bennet 的解决方案很有创意且简洁,我希望我能想到它。序列化到字符串可能会在紧要关头工作,但如果是我,我会尽量避免这种情况,因为它会在以后为您带来额外的问题,即反序列化这些字符串返回对象。不知道我是否理解您为什么不只使用单独的节点和关系,再次,这将发挥您正在使用的数据库的优势。
@WayneCordrey 当您使用Neo4jClient
时,您可以创建自己的Json 序列化程序并将其传递给客户端,然后客户端会将其用于您的类实例(请参阅***.com/questions/23132187/…)。 @FrobberOfBits 我完全同意你的看法,只是想确保有利基市场的人没有阅读评论然后放弃:)【参考方案3】:
除了这些答案,请注意,如果您不需要在任何查询中涉及子字段属性(例如,搜索 User.name 为“X”的 Tiles),您可以简单地序列化 在插入之前将对象字段转换为字符串(例如使用JSON.stringify
),并在从数据库读取时将它们反序列化。
当您想将结构化数据“附加”到节点时,这特别有用,但您不太关心这些数据与数据库中的关系(例如用户偏好)。
【讨论】:
以上是关于在 Neo4j 中将对象存储为属性的主要内容,如果未能解决你的问题,请参考以下文章
在 MySQL 中将 Java 对象存储为 BLOB:奇怪的错误