最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Mongoose - Generate ObjectID for each object before saving document - Stack Overflow

programmeradmin2浏览0评论

I want generate an ObjectID for each Object present inside my array. The thing is I'm getting the products with a .forEach statement from another server and push them inside my array without a Schema that generates an ObjectID....

Product Schema:

const productsSchema = new mongoose.Schema({

  apiKey: String,
  domain: String,
  totalcount: Number,
  totaldone: Number,
  allSKUS: Array,
  allProducts: Array,
  created_at: { type: Date },
  updated_at: { type: Date },

}, { collection: 'products', timestamps: true });

productsSchema.plugin(uniqueValidator);

const Products = mongoose.model('Products', productsSchema);

module.exports = Products;

My Code:

const newProduct = {

  apiKey: userApiProducts.apiKey,
  domain: userApiProducts.domain,
  totalcount: userApiProducts.totalcount,
  totaldone: userApiProducts.totaldone,
  allSKUS: userApiProducts.allSKUS,
  allProducts: userApiProducts.allProducts // generate ObjectID for each object that gets pushed inside the Array
};

Products.findOneAndUpdate( userApiProducts.domain, newProduct, {upsert:true} , (err, existingProducts) => {
  if (err) { return next(err); }
});

Output:

// Please Check ADD OBJECT ID HERE ment. This is where i want to generate an unique ObjectID before I push the data. I tried with var id = mongoose.Types.ObjectId(); but i'm afraid it will not be Unique...

{
        "_id" : ObjectId("58780a2c8d94cf6a32cd7530"),
        "domain" : "",
        "updatedAt" : ISODate("2017-01-12T23:27:15.465Z"),
        "apiKey" : "nf4fh3attn5ygkq1t",
        "totalcount" : 11,
        "totaldone" : 11,
        "allSKUS" : [
                "Primul",
                "Al doilea",
                "Al treilea"
        ],
        "allProducts" : [
            {
                // ADD OBJECT ID HERE
                "id": 1,
                "sku": "Primul",
                "name": "Primul",
                "status": 1,
                "total_images": 2,
                "media_gallery_entries": [
                    {
                        "id": 1,
                        "media_type": "image",
                        "label": null,
                        "position": 1,
                        "disabled": false,
                        "types": [
                            "image",
                            "small_image",
                            "thumbnail",
                            "swatch_image"
                        ],
                        "file": "/g/r/grafolio_angel_and_devil.png"
                    },
                    {
                        "id": 2,
                        "media_type": "image",
                        "label": null,
                        "position": 2,
                        "disabled": false,
                        "types": [],
                        "file": "/g/r/grafolio_angel_and_devil_thumbnail.jpg"
                    }
                ]
            },
            {
                // ADD OBJECT ID HERE
                "id": 3,
                "sku": "Al doilea",
                "name": "Al doilea",
                "status": 1,
                "total_images": 2,
                "media_gallery_entries": [
                    {
                        "id": 4,
                        "media_type": "image",
                        "label": null,
                        "position": 2,
                        "disabled": false,
                        "types": [],
                        "file": "/g/r/grafolio_angel_and_devil_thumbnail_1.jpg"
                    },
                    {
                        "id": 5,
                        "media_type": "image",
                        "label": null,
                        "position": 3,
                        "disabled": false,
                        "types": [],
                        "file": "/b/e/before.png"
                    }
                ]
            }, etc ......
        ],
        "__v" : 0,
        "createdAt" : ISODate("2017-01-12T22:58:52.524Z")
}

Is there any way of doing this without having to make a ton of DB Calls? I can't imagine saving like this

array.forEach((x)=> {
    Products.save({})
}) 

Hope someone has already worked on something similar and found the perfect solution for this !

I want generate an ObjectID for each Object present inside my array. The thing is I'm getting the products with a .forEach statement from another server and push them inside my array without a Schema that generates an ObjectID....

Product Schema:

const productsSchema = new mongoose.Schema({

  apiKey: String,
  domain: String,
  totalcount: Number,
  totaldone: Number,
  allSKUS: Array,
  allProducts: Array,
  created_at: { type: Date },
  updated_at: { type: Date },

}, { collection: 'products', timestamps: true });

productsSchema.plugin(uniqueValidator);

const Products = mongoose.model('Products', productsSchema);

module.exports = Products;

My Code:

const newProduct = {

  apiKey: userApiProducts.apiKey,
  domain: userApiProducts.domain,
  totalcount: userApiProducts.totalcount,
  totaldone: userApiProducts.totaldone,
  allSKUS: userApiProducts.allSKUS,
  allProducts: userApiProducts.allProducts // generate ObjectID for each object that gets pushed inside the Array
};

Products.findOneAndUpdate( userApiProducts.domain, newProduct, {upsert:true} , (err, existingProducts) => {
  if (err) { return next(err); }
});

Output:

// Please Check ADD OBJECT ID HERE ment. This is where i want to generate an unique ObjectID before I push the data. I tried with var id = mongoose.Types.ObjectId(); but i'm afraid it will not be Unique...

{
        "_id" : ObjectId("58780a2c8d94cf6a32cd7530"),
        "domain" : "http://example.",
        "updatedAt" : ISODate("2017-01-12T23:27:15.465Z"),
        "apiKey" : "nf4fh3attn5ygkq1t",
        "totalcount" : 11,
        "totaldone" : 11,
        "allSKUS" : [
                "Primul",
                "Al doilea",
                "Al treilea"
        ],
        "allProducts" : [
            {
                // ADD OBJECT ID HERE
                "id": 1,
                "sku": "Primul",
                "name": "Primul",
                "status": 1,
                "total_images": 2,
                "media_gallery_entries": [
                    {
                        "id": 1,
                        "media_type": "image",
                        "label": null,
                        "position": 1,
                        "disabled": false,
                        "types": [
                            "image",
                            "small_image",
                            "thumbnail",
                            "swatch_image"
                        ],
                        "file": "/g/r/grafolio_angel_and_devil.png"
                    },
                    {
                        "id": 2,
                        "media_type": "image",
                        "label": null,
                        "position": 2,
                        "disabled": false,
                        "types": [],
                        "file": "/g/r/grafolio_angel_and_devil_thumbnail.jpg"
                    }
                ]
            },
            {
                // ADD OBJECT ID HERE
                "id": 3,
                "sku": "Al doilea",
                "name": "Al doilea",
                "status": 1,
                "total_images": 2,
                "media_gallery_entries": [
                    {
                        "id": 4,
                        "media_type": "image",
                        "label": null,
                        "position": 2,
                        "disabled": false,
                        "types": [],
                        "file": "/g/r/grafolio_angel_and_devil_thumbnail_1.jpg"
                    },
                    {
                        "id": 5,
                        "media_type": "image",
                        "label": null,
                        "position": 3,
                        "disabled": false,
                        "types": [],
                        "file": "/b/e/before.png"
                    }
                ]
            }, etc ......
        ],
        "__v" : 0,
        "createdAt" : ISODate("2017-01-12T22:58:52.524Z")
}

Is there any way of doing this without having to make a ton of DB Calls? I can't imagine saving like this

array.forEach((x)=> {
    Products.save({})
}) 

Hope someone has already worked on something similar and found the perfect solution for this !

Share Improve this question asked Jan 13, 2017 at 0:50 Octavian LojnitaOctavian Lojnita 3614 silver badges16 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 4

If you want to add ObjectId automatically, you need to define a separate schema for it and set the _id options for the schema as true.

Do the following:

  • Change your productsSchema as CatalogueSchema (for ease of understanding).
  • Define a new ProductSchema for Product (element of allProducts)
  • In CatalogueSchema define allProducts type as [Product.schema]. This will automatically add _id (ObjectId).

Also, you don't need to add created_at and updated_at as part of schema when you set timestamps option as true.

Catalogue Schema

const Product = require('Product_Schema_Module_Path'); // Edit

const CatalogueSchema = new mongoose.Schema({

    apiKey: String,
    domain: String,
    totalcount: Number,
    totaldone: Number,
    allSKUS: Array,
    allProducts: [Product.schema]   
    // Note the change here (Array -> [Product.schema]
  // Creating a separate schema ensures automatic id (ObjectId)

}, { collection: 'catalogue', timestamps: true });

CatalogueSchema.plugin(uniqueValidator);

const Catalogue = mongoose.model('Catalogue', CatalogueSchema);
module.exports = Catalogue;

Product Schema (New schema to ensure adding of ObjectId)

const ProductSchema = new mongoose.Schema({

    id: Number,
    sku: String,
    name: String,
    status: Number,
    total_images: Number,
    media_gallery_entries: Array

}, { _id: true, timestamps: true });  
// _id option is true by default. You can ommit it.
// If _id is set to false, it will not add ObjectId

ProductSchema.plugin(uniqueValidator);

const Product = mongoose.model('Product', ProductSchema);
module.exports = Product;

EDIT (Save Products in Catalogue)

(Also, note that you have to require the ProductSchema module in your CatalogueSchema module)

// Map userApiProducts.allProducts to array of Product documents
const products = userApiProducts.allProducts.map(product => {
    return new Product(product);
})

const newProduct = {
    apiKey: userApiProducts.apiKey,
    domain: userApiProducts.domain,
    totalcount: userApiProducts.totalcount,
    totaldone: userApiProducts.totaldone,
    allSKUS: userApiProducts.allSKUS,
    allProducts: products
};

Catalogue
    .findOneAndUpdate({ domain: userApiProducts.domain }, newProduct, { upsert:true } , (err, products) => {
    // Handle error
});

To add multiple documents into Mongo you can use db.collection.insert():

  • https://docs.mongodb./manual/reference/method/db.collection.insert/

In Mongoose you can use Model.insertMany():

  • http://mongoosejs./docs/api.html#model_Model.insertMany

But keep in mind that when you have one document inside of other document in Mongoose they are not actually stored like that in Mongo. Mongo only stores the IDs of the child documents and not their contents in the parent document - and not even any info on which collection those IDs belong to.

When you use population then Mongoose actually retrieves the relevant documents from the DB in separate requests to Mongo. So, population is a concept of Mongoose. Mongo just stores the IDs, so you need to create the documents first before you can insert the IDs.

The thing that you are trying to do would be easy without using Mongoose. You can store multiple documents in one request in Mongo using your own IDs if you want and you can store another document with an array of those IDs in another request.

Of course however you do it you will get inconsistent state during the operation because Mongo doesn't support transactions.

发布评论

评论列表(0)

  1. 暂无评论