问题
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 comment. 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.com",
"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 !
回答1:
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
asCatalogueSchema
(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
});
回答2:
To add multiple documents into Mongo you can use db.collection.insert()
:
- https://docs.mongodb.com/manual/reference/method/db.collection.insert/
In Mongoose you can use Model.insertMany()
:
- http://mongoosejs.com/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.
来源:https://stackoverflow.com/questions/41625689/mongoose-generate-objectid-for-each-object-before-saving-document