Best approach for nested data?

System Information
  • Strapi Version: 3.1.1
  • Operating System: Windows 10
  • Database: MongoDB
  • Node Version: 12.18.2
  • NPM Version: 6.14.5
  • Yarn Version: 1.22.4

Hello,

I’m trying to create orders for an e-commerce application (later, I’ll implement Stripe). I already have Users, and Products content-types. Here is what I want to do, creating Orders content-type:

Do you have any idea on what I should use in Strapi ? I tried content-types, dynamic zones and components and I almost got this, but I couldn’t make it. I just need some help for the “details” part.

Hello @Pierre,

You can’t directly obtain nested data inside the content-type, but here is a workaround:
First of all, here is the result that I obtained:

Orders: {
    "_id": "5fa41a5fed71373bb3f4fc66",
    "amount": 1111,
    "status": "pending",
    "order_details": [
        {
            "_id": "5fa41a6ced71373bb3f4fc67",
            "quantity": 2,
            "name": "iPhone 12 x 2",
            "product": "5fa41a4ced71373bb3f4fc65"
        },
        {
            "_id": "5fa4192432803d3af0f5d71b",
            "quantity": 100,
            "name": "Samsung TV x 100",
            "product": "5fa418f832803d3af0f5d719"
        }
    ],
    "user": {
        "_id": "5fa16b953940762a47f2838a",
        "username": "test",
        "email": "testtesttesttest@gmail.com",
        "provider": "local",
        "role": "5fa1584d56e6e917c29eabc2",
    }
}

Orders content-type (User has many Orders, Order has many Order-Details):

image

Order-details content-type (Order-Detail has one Product):

image

Note: order_details.name is generated inside lifecycle, by concatenating product name & quantity so I could obtain this view inside Orders Content-type:
image

async beforeCreate(data, model) {
      let product = await strapi.query('products').findOne({ id: data.product });
      data.name = `${product.name} x ${data.quantity}`;
},
async beforeUpdate(data, model) {
      let product = await strapi.query('products').findOne({ id: model.product });
      model.name = `${product.name} x ${model.quantity}`;
    },
1 Like

Thank you so much @sunnyson for your answer !! :star_struck:

This is a very clear solution !
So I tried this workaround, I have a question about it: to create an Order, do I need to create an OrderDetail first ??
I’m not sure about how to implement this, since I’ll create orders through a POST request on /orders. Should I do first a POST request on /order_details then ?

Thank you very much anyway !!

First, overwrite the order’s create() controller and define all that business logic there. Inside it you need to create the order-details first (because you need their IDs to refer them in the relation of order), then you create the order with a reference to order-details.

That way you will have a single controller that creates both: order-details and order. Now you can make a single POST request to /orders from your front-end.

Thank you again @sunnyson !

There is something wrong. My client needs to be able, from the administrative panel, to check the orders her clients have paid so she can send them their product(s). Right now she has only the ids of OrderDetails in Orders in the admin panel. Should I use a component for this ?

Also when I think about it, I don’t need OrderDetails to be a Content-Type since I won’t do any request on it.

I just need a nested “details” (products and quantity for each one inside) in “orders”.
This is very basic normally, I don’t get why it’s that hard :thinking:

Btw is it normal controller isn’t call (to check the body of Strapi’s requests for example) ? It only goes through my create(ctx) function while I use API requests, not directly Strapi. I would like to be able to have control on both (Strapi’s administrative panel and API requests). If it’s not the case, I guess I’ll have to duplicate the code ?

You should modify the layout of component to display Order details name.

Of course, you can use it as a model only.

Create a repeatable component inside Orders, which contains the: ID of the product, name, quantity, calculated price and etc.

Indeed you can skip the usage of relation with order-details at all. The easiest method is to create a repeatable component for that.

Thank you for your detailed answers :slight_smile:

For those who would like to know, I created a simple repeatable component (as @sunnyson suggested) named “details” into my Order content-type and it worked pretty well ! :smile:
This component has a “Order-Details” category, and inside there are:

  • quantity: Number
  • product: relation with Products: Order has one Product
1 Like

Just something to keep in mind, you can’t use any of our default filters on components:

hello! any chance you could screenshot the structure? im having a problem with outputing existing data using mongodb.
my structure is

orders is the name of the collection

orders{
     customer{
     id,
    name,
     }
}

i already tried using repeatable component but it doest work