0

I'm trying to create a help page for a website using mongodb and graphql. I've made this schema (joiGoose Schema) for the help pages:

constructor()
{
    const joiSchema = joi.object
    ({
        url: joi.string().required(),
        title: joi.string().required(),

        content: joi.string().required(),

        children: joi.array().items
        (
            joi.string().meta({ _mongoose: { type: "ObjectId", ref: "Help" } }).optional(),
        ).meta({ _mongoose : { _id: false, timestamps: false } }),

        published: joi.boolean().default(true).required(),

        createdAt: joi.date().required().default(() => moment()),
        updatedAt: joi.date().required().default(() => moment()),
    });
        
    const mongooseSchema = super(joigoose.convert(joiSchema));
    return mongooseSchema;
}

The first thing I want to do is to give the summary of the help section. I get all the pages from mongodb using the following query :

const allHelpPages = await MONGO.Help.find();`

It gives me an array containing all the help pages. As each page can have multiple nested children pages (there is no maximum level), what I need is to reduce the array with the children for all the pages.

Example:

const allPages = 
[
    {
        id: 1,
        title: Test 1,
        children:
        [
            2,
            3
        ]
    },
    {
        id: 2,
        title: Test 2,
        children:
        [
            4,
            5
        ]
    }
    {
        id: 3,
        title: Test 3,
        children:
        [
            6
        ]
    }
    {
        id: 4,
        title: Test 4
    }
    {
        id: 5,
        title: Test 5
    }
    {
        id: 6,
        title: Test 6,
        children:
        [
            7
        ]
    }
    {
        id: 7,
        title: Test 7
    }
]

Should end to :

[
    {
        id: 1,
        title: Test 1,
        children:
        [
            {
                id: 2,
                title: Test 2,
                children:
                [
                    {
                        id: 4,
                        title: Test 4
                    },
                    {
                        id: 5,
                        title: Test 5
                    }
                ]
            },
            {
                id: 3,
                title: Test 3,
                children:
                [
                    {
                        id: 6,
                        title: Test 6,
                        children:
                        [
                            {
                                id: 7,
                                title: Test 7
                            }
                        ]
                    }
                ]
            }
        ]
    },
]
7
  • What have you tried so far to solve this on your own? Commented Oct 10, 2020 at 14:36
  • const ordered = allPages.map(p => { if(p.children && p.children.length) { const children = p.children.map(c => { const index = allPages.findIndex(p => p._id.toString() === c.toString()); const spliced = allPages.splice(index, 1); return spliced[0]; }); p.children = children; } return p; }); Commented Oct 10, 2020 at 14:39
  • Iterate over allPages. For each "page" iterate over the children. For each child get the corresponding entry in allPages and replace the id in children with the "page". Remove the "page" from allPages. Commented Oct 10, 2020 at 14:39
  • How id: 6 becomes a child of id: 3? Maybe clean up your Q code for two objects. Also, your Q is a little general and Confusing. Commented Oct 10, 2020 at 14:40
  • Don't put relevant stuff in a comment -> Edit your question. Commented Oct 10, 2020 at 14:40

1 Answer 1

1

You could create one object that you can use as a lookup table where keys are ids of objects. And then based on that object you can modify children arrays with actual objects and in the end just filter out objects that are children of some other object.

const data = [{"id":1,"title":"Test 1","children":[2,3]},{"id":2,"title":"Test 2","children":[4,5]},{"id":3,"title":"Test 3","children":[6]},{"id":4,"title":"Test 4"},{"id":5,"title":"Test 5"},{"id":6,"title":"Test 6","children":[7]},{"id":7,"title":"Test 7"}]

const map = {}, isChild = {}

for (let o of data) {
  map[o.id] = o
}

const result = Object.entries(map)
  .map(([k, v]) => {
    const children = v.children;

    if (children) children.forEach((id, i) => {
      isChild[id] = true
      children[i] = map[id]
    })

    return { ...v, children}
  })
  .filter(({ id }) => !isChild[id])

console.log(result)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.