MATCH (u:User {publicId: '${data.userId}'})
OPTIONAL MATCH (follower)-[:FOLLOWS]->(u)
OPTIONAL MATCH (post)-[:HAS_CONTENT]->(content:PostContent)
WHERE post.userId IN [follower.publicId, u.publicId]
MATCH (postUser:User {publicId: post.userId})
OPTIONAL MATCH (post)-[:TAG_IN]->(taggedUser:User)
OPTIONAL MATCH (post)-[:SHOULD_SEE]-(specific:User)
WITH post, content, postUser,
COLLECT(DISTINCT taggedUser) AS taggedUsers,
COLLECT(DISTINCT specific) AS specificUsers,
COLLECT(DISTINCT follower) AS followers
WITH post, content, postUser, taggedUsers, specificUsers, followers,
{
post: post,
content: content,
taggedUsers: taggedUsers,
specificUsers: specificUsers,
user: postUser,
follower: followers
} AS postDetails
WITH COLLECT(DISTINCT {
post: post,
content: content,
taggedUsers: taggedUsers,
specificUsers: specificUsers,
user: postUser
}) AS filteredPostsstrong text
WITH [p IN filteredPosts WHERE
p.post.visibility <> 'onlyme' OR
(p.post.visibility = 'onlyme' AND p.user.publicId = '${data.userId}')] AS finalPosts
RETURN finalPosts; visibility wise post show public onlyme specific followers
Just a comment, it looks like you are relating posts to their user by a user id stored on the post. You should not do that. You should have a relationship between the two nodes so you easily get them. You are doing a join-like search each time, which is not very “graphy”, but more like a relational db.
Also, why the optional matches? You use the values from those matches, so the query is not going to proceed anyway when no match is found.
Finally, your chaining of uncorrelated matches causes Cartesian products. I suggest you use a “collect subquery” instead.
1 Like
my question module.exports.createPost = async (userId, data) => {
const session = driver.session();
try {
console.log("data", data);
const randomId = Math.floor(Math.random() * 500 + 1);
const generator = UUID(randomId);
let id = generator.uuid();
const description = data.description
? data.description.slice(0, 1500).trim().replace(/'/g, "\'")
: "";
const visibility = data.visibility || "public";
let visibilityQuery = "";
if (visibility == "followers") {
visibilityQuery = `
MATCH (follower:User)-[:FOLLOWS]->(u:User {publicId:'${userId}'})
`;
} else if (visibility === "specific") {
const specific = data.specific || [];
visibilityQuery = `
MATCH (targetUser:User) WHERE targetUser.publicId IN ${JSON.stringify(
specific
)}
WITH targetUser, u,post
MERGE (targetUser)-[:SHOULD_SEE]->(post)
WITH u,post
MERGE (u)-[:SHOULD_SEE]->(post)
`;
} else if (visibility === "onlyme") {
visibilityQuery = `
MATCH (u:User)-[:POSTED]->(post) WHERE u.publicId='${userId}'
MERGE (u)-[:SHOULD_SEE]->(post)
`;
}
const contentArray = data.content || [];
let imageQueries = "";
contentArray.forEach((content, index) => {
const imageQuery = `
MERGE (pc${index}:PostContent {
image: '${content.file}',
postId: '${id}',
mimeType: '${content.mimeType}'
})
MERGE (post)-[:HAS_CONTENT]->(pc${index})
`;
imageQueries += imageQuery;
});
const deletedAtQuery =
data.deletedAt !== undefined ? `, deletedAt: ${data.deletedAt}` : "";
const query = `
MATCH (u:User{publicId:'${userId}'})
MERGE (post:Post {
userId: '${userId}',
postId: '${id}',
description: '${description}',
createdAt: datetime()${deletedAtQuery},
visibility: '${data.visibility}'
})
with u,post
MERGE (u)-[:POSTED {status:'${data.visibility}'}]->(post)
WITH u, post
${visibilityQuery}
${imageQueries}
RETURN post;
`;
const result = await session.run(query);
// console.log("result Result:", result);
if (result.records && result.records.length > 0) {
return result.records[0].get("post").properties;
} else {
return false;
}
} catch (error) {
console.error("Error creating post:", error);
return false;
} finally {
await session.close();
}
}; this condition wise getposts query
How to get Posts onlyme followers specific users and public
There is too much info. Let's break it down and resolve pieces at a time. I see from your visualization of your data that you do have relationships between entities. You should use these in your query and not join via 'id' values.
Let's start by defining your data model. Does this look accurate? Can a Post have multiple related PostContent nodes, or just one?
Using the diagram, can you describe what information you want to return?
From your first post, it looks like you want to do something like this:
- find a User by a 'userId' passed as a query parameter
- find all the User's followers (which are other Users)
- find all the posts of the User and of each follower
- for each Post, find the User that posted, the tagged users of the Post, and the Users that should see the post
- for each Post, collect all the Users tagged in the Post, collect all the Users who should see the post, and collect all the followers (Users) of the User that posted the Post.
Is any of this correct?
above diagram correct
const query = `
MATCH (me:User {publicId: '${data.userId}'})
OPTIONAL MATCH (me)-[:POSTED]->(mine:Post)-[:HAS_CONTENT]->(mineContent:PostContent)
OPTIONAL MATCH (userInfo:User {publicId: mine.userId})-[:POSTED]->(mine)
OPTIONAL MATCH (user:User)-[:POSTED]->(publicPost:Post {visibility: 'public'})-[:HAS_CONTENT]->(publicContent:PostContent)
OPTIONAL MATCH (me)-[:FOLLOWS]->(follower:User)-[:POSTED]->(followerPost:Post)-[:HAS_CONTENT]->(followerContent:PostContent)
OPTIONAL MATCH (mine)-[:TAG_IN]->(mineTags:User)
OPTIONAL MATCH (publicPost)-[:TAG_IN]->(publicPostTags:User)
OPTIONAL MATCH (followerPost)-[:TAG_IN]->(followerPostTags:User)
WITH me,
COLLECT(DISTINCT {post: mine, content: mineContent, creator: userInfo, tags: mineTags}) +
COLLECT(DISTINCT {post: publicPost, content: publicContent, creator: user, tags: publicPostTags}) +
COLLECT(DISTINCT {post: followerPost, content: followerContent, creator: follower, tags: followerPostTags}) AS posts
UNWIND posts AS postInfo
WITH me, postInfo.post AS post, postInfo.content AS content, postInfo.creator AS creator, postInfo.tags AS taggedUsers
WITH me, post, content, creator, taggedUsers,
CASE
WHEN post.visibility = 'onlyme' AND post.userId = me.publicId THEN true
WHEN post.visibility = 'specific' AND post.userId = me.publicId THEN true
WHEN post.visibility = 'followers' OR post.visibility = 'public' THEN true
ELSE false
END AS canSeePost
WHERE canSeePost OR canSeePost IS NULL
RETURN
COLLECT(DISTINCT {post: post, content: content, user: creator, taggedUsers: taggedUsers}) AS posts
SKIP ${data.offset}
LIMIT ${data.limit};
`;
how to sort this query because response time 56second and this quer limit not work
{
"results": [
{
"post": {
"visibility": "public",
"description": "Description1",
"postId": "9831196306686243",
"userId": "1005055351656459"
},
"content": [
{
"image": "image.png",
"postId": "9831196306686243",
"mimeType": "image/jpeg"
}
],
"taggedUsers": ,
"specificUsers": ,
"user": {
"image": "image12",
"createdAt": "Wed Jan 17 2024 18:22:07 GMT+0530 (India Standard Time)",
"name": "user12",
"bio": "bio12",
"isPrivate": "FALSE",
"email": "a1@gmail.com12",
"authId": "cQdQNPFVUfMIhbODaZvUSFj3qm21",
"publicId": "1005055351656459"
}
},
{},
{}
] this type response