title: How do you seed a mongodb database such that the Keystone 5 CMS recognizes the many-to-many relationships?
body: <p>Let's say I have two objects: Product and Seller</p>
  <p>Products can have multiple Sellers.
  A single Seller can sell multiple Products.</p>
  <p>The goal is to write a seeding script that successfully seeds my MongoDB database such that Keystone.js's CMS recognizes the many-to-many relationship.</p>
  <h2>Schemas</h2>
  <p><code>Product.ts</code></p>
  <pre><code>import { text, relationship } from &quot;@keystone-next/fields&quot;;
  import { list } from &quot;@keystone-next/keystone/schema&quot;;
  
  export const Product = list({
    fields: {
      name: text({ isRequired: true }),
      sellers: relationship({
        ref: &quot;Seller.products&quot;,
        many: true,
      }),
    },
  });
  
  </code></pre>
  <p><code>Seller.ts</code></p>
  <pre><code>import { text, relationship } from &quot;@keystone-next/fields&quot;;
  import { list } from &quot;@keystone-next/keystone/schema&quot;;
  
  export const Product = list({
    fields: {
      name: text({ isRequired: true }),
      products: relationship({
        ref: &quot;Product.sellers&quot;,
        many: true,
      }),
    },
  });
  </code></pre>
  <h2>KeystoneJS config</h2>
  <p>My <code>keystone.ts</code> config, shortened for brevity, looks like this:</p>
  <pre><code>import { insertSeedData } from &quot;./seed-data&quot;
  ...
  db: {
    adapter: &quot;mongoose&quot;,
    url: databaseURL,
    async onConnect(keystone) {
      console.log(&quot;Connected to the database!&quot;);
      if (process.argv.includes(&quot;--seed-data&quot;)) {
        await insertSeedData(keystone);
      }
    },
  },
  lists: createSchema({
    Product,
    Seller,
  }),
  ...
  </code></pre>
  <h2>Seeding Scripts (these are the files I expect to change)</h2>
  <p>I have a script that populates the database (<code>seed-data/index.ts</code>):</p>
  <pre><code>import { products } from &quot;./data&quot;;
  import { sellers } from &quot;./data&quot;;
  
  export async function insertSeedData(ks: any) {
  
    // setup code
    const keystone = ks.keystone || ks;
    const adapter = keystone.adapters?.MongooseAdapter || keystone.adapter;
    const { mongoose } = adapter;
    mongoose.set(&quot;debug&quot;, true);
  
    // adding products to DB
    for (const product of products) {
      await mongoose.model(&quot;Product&quot;).create(product);
    }
  
    // adding sellers to DB
    for (const seller of sellers) {
      await mongoose.model(&quot;Seller&quot;).create(seller);
    }
  }
  </code></pre>
  <p>And finally, <code>data.ts</code> looks something like this:</p>
  <pre><code>export const products = [
    {
      name: &quot;apple&quot;,
      sellers: [&quot;Joe&quot;, &quot;Anne&quot;, &quot;Duke&quot;, &quot;Alicia&quot;],
    },
    {
      name: &quot;orange&quot;,
      sellers: [&quot;Duke&quot;, &quot;Alicia&quot;],
    },
    ...
  ];
  export const sellers = [
    {
      name: &quot;Joe&quot;,
      products: [&quot;apple&quot;, &quot;banana&quot;],
    },
    {
      name: &quot;Duke&quot;,
      products: [&quot;apple&quot;, &quot;orange&quot;, &quot;banana&quot;],
    },
    ...
  ];
  </code></pre>
  <p>The above setup does not work for a variety of reasons. The most obvious is that the <code>sellers</code> and <code>products</code> attributes of the <code>Product</code> and <code>Seller</code> objects (respectively) should reference objects (<code>ObjectId</code>) and not names (e.g. &quot;apple&quot;, &quot;Joe&quot;).</p>
  <p>I'll post a few attempts below that I thought would work, but did not:</p>
  <h2>Attempt 1</h2>
  <p>I figured I'd just give them temporary ids (the <code>id</code> attribute in <code>data.ts</code> below) and then, once MongoDB assigns an <code>ObjectId</code>, I'll use those.</p>
  <p><code>seed-data/index.ts</code></p>
  <pre><code>...
    const productIdsMapping = [];
  ...
    // adding products to DB
    for (const product of products) {
      const productToPutInMongoDB = { name: product.name };
      const { _id } = await mongoose.model(&quot;Product&quot;).create(productToPutInMongoDB);
      productIdsMapping.push(_id);
    }
  
    // adding sellers to DB (using product IDs created by MongoDB)
    for (const seller of sellers) {
      const productMongoDBIds = [];
      for (const productSeedId of seller.products) {
        productMongoDBIds.push(productIdsMapping[productSeedId]);
      const sellerToPutInMongoDB = { name: seller.name, products: productMongoDBIds };
      await mongoose.model(&quot;Seller&quot;).create(sellerToPutInMongoDB);
    }
  ...
  </code></pre>
  <p><code>data.ts</code></p>
  <pre><code>export const products = [
    {
      id: 0,
      name: &quot;apple&quot;,
      sellers: [0, 1, 2, 3],
    },
    {
      id: 1,
      name: &quot;orange&quot;,
      sellers: [2, 3],
    },
    ...
  ];
  export const sellers = [
    {
      id: 0
      name: &quot;Joe&quot;,
      products: [0, 2],
    },
    ...
    {
      id: 2
      name: &quot;Duke&quot;,
      products: [0, 1, 2],
    },
    ...
  ];
  </code></pre>
  <h3>Output (attempt 1):</h3>
  <p>It just doesn't seem to care about or acknowledge the <code>products</code> attribute.</p>
  <pre><code>Mongoose: sellers.insertOne({ _id: ObjectId(&quot;$ID&quot;), name: 'Joe', __v: 0}, { session: null })
  {
    results: {
      _id: $ID,
      name: 'Joe',
      __v: 0
    }
  }
  </code></pre>
  <h2>Attempt 2</h2>
  <p>I figured maybe I just didn't format it correctly, for some reason, so maybe if I queried the products and shoved them directly into the seller object, that would work.</p>
  <p><code>seed-data/index.ts</code></p>
  <pre><code>...
    const productIdsMapping = [];
  ...
    // adding products to DB
    for (const product of products) {
      const productToPutInMongoDB = { name: product.name };
      const { _id } = await mongoose.model(&quot;Product&quot;).create(productToPutInMongoDB);
      productIdsMapping.push(_id);
    }
  
    // adding sellers to DB (using product IDs created by MongoDB)
    for (const seller of sellers) {
      const productMongoDBIds = [];
      for (const productSeedId of seller.products) {
        productMongoDBIds.push(productIdsMapping[productSeedId]);
      }
      const sellerToPutInMongoDB = { name: seller.name };
      const { _id } = await mongoose.model(&quot;Seller&quot;).create(sellerToPutInMongoDB);
      const resultsToBeConsoleLogged = await mongoose.model(&quot;Seller&quot;).findByIdAndUpdate(
        _id,
        {
          $push: {
            products: productMongoDBIds,
          },
        },
        { new: true, useFindAndModify: false, upsert: true }
      );
    }
  ...
  </code></pre>
  <p><code>data.ts</code></p>
  <p>Same data.ts file as attempt 1.</p>
  <h3>Output (attempt 2):</h3>
  <p>Same thing. No luck on the <code>products</code> attribute appearing.</p>
  <pre><code>Mongoose: sellers.insertOne({ _id: ObjectId(&quot;$ID&quot;), name: 'Joe', __v: 0}, { session: null })
  {
    results: {
      _id: $ID,
      name: 'Joe',
      __v: 0
    }
  }
  </code></pre>
  <p>So, now I'm stuck. I figured attempt 1 would Just Work™ like this answer:</p>
  <p><a href="https://stackoverflow.com/a/52965025">https://stackoverflow.com/a/52965025</a></p>
  <p>Any thoughts?</p>