Creating threaded comment object from an array of comments with ancestors - reactjs

I am working on a simple MERN app and I am trying to implement a nested comment section.
Currently I am able to create new comments and replies of comments. The resulting comment documents (see below) have a 'parents' field which is an array of the objectIds for the parent comments.
I can retrieve all comments associated with a post, filter the root comments and create a sorted list of the replies under each root comment.
I have a recursive React comment component built, but I am struggling to take the arrays and push the comments into an an array or object with a structure that allows me to then recursively render the comments in React.
// This is a sample document mongoDB document
{
"_id": { "$oid": "6292fa410809d3874a5d742d" },
"user": { "$oid": "6277297675616d3a21cbbf7a" },
"username": "whenInRome",
"list": { "$oid": "62816f570ebefe01c72dc3de" },
"listUser": { "$oid": "627598950839cf6d62e2ad85" },
"message": "You know, I really like Amatriciana myself!",
"parents": [
{ "$oid": "6291ce46aeb4a89ae4df8dac" },
{ "$oid": "6292fa410809d3874a5d742d" }
],
// And this is my code for manipulating the array of retrieved comment documents:
const { comments } = listContext;
const thread = [];
const rootComments = comments.filter((comment) => comment.parents.length < 2);
rootComments.forEach((rootComment) => {
const replies = comments
.filter((comment) => comment.parents[0] === rootComment.parents[0])
.sort((a, b) => b.parents.length - a.parents.length);
replies.forEach(reply => {
if (reply.parents.length > 1) {
let parentComment = reply.parents[reply.parents.length - 2];
Any suggestions for converting these sorted arrays into a structured comment thread would be really appreciated!
Thanks!

Related

Search Flow in MERN Stack

First of all, I tried searching a lot but I am not able to find any resource which satisfies my need. I know there might be some answers already, if you know one please help with the link.
I know how to show search suggestions but I don't know how to show full search results when someone clicks on a search suggestion. Like how to do that in MERN stack with an example if possible.
I need a solution that best fits my scenario:
I have three models,
tags - holds tags
categories - holds categories
items - holds items data - has categories and tags both
currently, I am not storing references to categories and tags table instead
storing a copy directly inside items
Now, I basically want to search the items having the specific categories and tags when someone searches for a keyword.
What I am doing currently is, I search for tags matching the keyword, then categories, then taking out their _id(s) and finding that in items collection
const tags = await Tags.find(
{ tag: { $regex: category.toString(), $options: "i" } },
{ projection: { createdBy: 0 } });
const categories = await Categories.find(
{ category: { $regex: category.toString(), $options: "i" } },
{ projection: { createdBy: 0 } });
const tagsIdArray = tags.map((item) => new ObjectId(item._id));
const catIdArray = categories.map((item) => new
Object(item._id));
$match: {
$and: [
{
$or: [
{ "tags._id": { $in: [...tagsIdArray] } },
{ "category._id": { $in: [...catIdArray] } },
],},],},
And I know that this is not the best way, and it takes a lot of time to search for a given keyword.
Please suggest me schema structure and way to implement search with suggestions.

Delete many items from array of documents in mongodb that match this value

I am trying to delete all documents from an array of documents that match this value but cannot figure it out,
This is my delete query that is not working, courses is the array I need to be in and code is the document I need to check to see its value for deletetion. So if courses.code == 123, then delete and keep going sort of thing.
result = await mongoClient.db(DB_NAME).collection("technologies").deleteMany({ 'courses': {$in: 'courses.code'} });
That is what it looks like in my collection.
"name": "Sass",
"description": "Sass (Syntactically awesome style sheets) is a preprocessor scripting language that is interpreted or compiled into Cascading Style Sheets (CSS).",
"difficulty":2,
"courses":[
{"code":"PROG2700","name":"Client Side Programming"},
{"code":"PROG3017","name":"Full Stack Programming"}
]
},
Any help would be great, thanks!
You can filter documents that contain the field you want to update
Do tests before updates on the original collection.
After some searches, I've found this method:
const filter = { }
db.collection.update(filter,
{
$pull: {
"courses": {
code: {
$in: [
"PROG3017",
"PROG2700"
]
}
}
}
},
{
multi: true
})
This pulls out any element in the array where the value of code is $in the array.

How to write a test for nested JSON response from enterprise application

I'm trying to use Postman as a test tool to validate that our customers all have a mailing address in our master system. I'm having trouble drilling down into the JSON due to its structure. Each response is an array structure with a single "node" that has no "head attribute" to address.
Example JSON:
[
{
"ID": "cmd_org_628733899",
"organization": {
"name": "FULL POTENTIAL",
"accountStatusCode": "1",
"accountStatusDescription": "OPEN"
},
"location": [
{
"locality": "LITTLE ROCK",
"locationType": "MAILING"
},
{
"locality": "BIG ROCK",
"locationType": "LOCATION"
}
]
}
]
Test code as it exists:
pm.test("Check for a Mailing Address", function () {
// Parse response body
var jsonData = pm.response.json();
// Find the array index for the MAILING Address
var mailingLocationIndex = jsonData.location.map(
function(filter) {
return location.locationType;
}
).indexOf('MAILING');
// Get the mailing location object by using the index calculated above
var mailingLocation = jsonData.location[mailingFilterIndex];
// Check that the mailing location exists
pm.expect(mailingLocation).to.exist;
});
Error message: TypeError: Cannot read property 'map' of undefined
I understand that I have to iterate to node(0) in the outer array and then drill into the nested location array to find an entry with a locationType = Mailing.
I can't get past the outer array. I'm new to JavaScript and JSON parsing - I am a COBOL programmer.
Knowing nothing else, I would say you mean this
pm.test("Check for a Mailing Address", function () {
var mailingLocations = pm.response.json().location.filter(function (item) {
return item.locationType === 'MAILING';
});
pm.expect(mailingLocations).to.have.lengthOf(1);
});
You want to filter out all the locations that have a MAILING type and there should be exactly one, or at least one, depending.
Whether pm.response.json() actually returns the object you show in your question is impossible to say from where I'm standing.
In modern JS, the above is shorter:
pm.test("Check for a Mailing Address", function () {
var mailingLocations = pm.response.json().location.filter(item => item.locationType === 'MAILING');
pm.expect(mailingLocations).to.have.lengthOf(1);
});

I try to implement a connection using relay and all the node's IDs are the same

I write a really simple schema using graphql, but some how all the IDs in the edges are the same.
{
"data": {
"imageList": {
"id": "SW1hZ2VMaXN0Og==",
"images": {
"edges": [
{
"node": {
"id": "SW1hZ2U6",
"url": "1.jpg"
}
},
{
"node": {
"id": "SW1hZ2U6",
"url": "2.jpg"
}
},
{
"node": {
"id": "SW1hZ2U6",
"url": "3.jpg"
}
}
]
}
}
}
}
I posted the specific detail on github here's the link.
So, globalIdField expects your object to have a field named 'id'. It then takes the string you pass to globalIdField and adds a ':' and your object's id to create its globally unique id.
If you object doesn't have a field called exactly 'id', then it wont append it, and all your globalIdField will just be the string you pass in and ':'. So they wont be unique, they will all be the same.
There is a second parameter you can pass to globalIdField which is a function that gets your object and returns an id for globalIdField to use. So lets say your object's id field is actually called '_id' (thanks Mongo!). You would call globalIdField like so:
id: globalIdField('Image', image => image._id)
There you go. Unique IDs for Relay to enjoy.
Here is the link to the relevant source-code in graphql-relay-js: https://github.com/graphql/graphql-relay-js/blob/master/src/node/node.js#L110
paste the following code in browser console
atob('SW1hZ2U6')
you will find that the value of id is "Image:".
it means all id property of records fetched by (new MyImages()).getAll()
is null.
return union ids or I suggest you define images as GraphQLList
var ImageListType = new GraphQL.GraphQLObjectType({
name: 'ImageList',
description: 'A list of images',
fields: () => ({
id: Relay.globalIdField('ImageList'),
images: {
type: new GraphQLList(ImageType),
description: 'A collection of images',
args: Relay.connectionArgs,
resolve: (_, args) => Relay.connectionFromPromisedArray(
(new MyImages()).getAll(),
args
),
},
}),
interfaces: [nodeDefinition.nodeInterface],
});

Trouble with updating object properties in AngularJs

I am building my first app in AngularJs.
Here is the plunkr with what I've done so far. The user should be able to add new websites and group them in groups. Groups are also made by the user. Any time the new group is created it is available for new websites. What app should also do is to update group objects with newly assigned websites... and this is where I fail.
Here is how json should look like:
{
"sites": [
{
"url": "http://sfdg",
"id": 0,
"groups": [
{
"name": "adsf",
"id": 0
}
]
}
],
"groups": [
{
"name": "adsf",
"id": 0,
"sites": [//sites assigned
]
}
]
}
In the plunkr code I used push but that just adds new group...
Could you please direct me to the right way of achieving this.
Thanks!
To prevent circular references (a website object refers to a group object that refers to the website object, etc...), I would store id's to the relevant objects instead.
First, when creating a new group, add an empty sites array to it:
function createGroup(newGroup) {
newGroup.sites = []; // <-- add empty array of sites
$scope.groups.push(newGroup);
newGroup.id = groupIdSeq;
groupMap[newGroup.id] = newGroup;
groupIdSeq++;
return newGroup;
}
Then, when you create a new site, update each group to which the site is added:
function createSite(newSite, groups) {
$scope.sites.push(newSite);
newSite.id = siteIdSeq;
sitesMap[newSite.id] = newSite;
// instead of storing the groups array, only store their id:
newSite.groups = groups.map(function(group) { return group.id });
// and add this new sites id to the groups' sites array.
groups.forEach(function(group) {
group.sites.push(newSite.id);
});
siteIdSeq++;
return newSite;
}
(updated plunker here)

Resources