#javascript #mongodb #mongoose
#javascript #node.js #mongoose #mongoose-схема #objectid
Вопрос:
Я хочу сгенерировать ObjectId для каждого объекта, присутствующего внутри моего массива. Дело в том, что я получаю продукты с помощью .Оператор forEach с другого сервера и помещает их внутрь моего массива без схемы, которая генерирует ObjectId….
Схема продукта:
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;
Мой код:
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); }
});
Вывод:
// 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")
}
Есть ли какой-либо способ сделать это без необходимости выполнять тонну вызовов DB? Я не могу представить сохранение таким образом
array.forEach((x)=> {
Products.save({})
})
Надеюсь, кто-то уже работал над чем-то подобным и нашел идеальное решение для этого!
Ответ №1:
Если вы хотите добавлять ObjectId
автоматически, вам нужно определить для него отдельную схему и установить для _id
параметров схемы значение true.
Выполните следующее:
- Измените свой
productsSchema
какCatalogueSchema
(для простоты понимания). - Определите новый
ProductSchema
для продукта (элемент allProducts) - В
CatalogueSchema
определить тип allProducts как[Product.schema]
. Это автоматически добавит_id
(ObjectId
).
Кроме того, вам не нужно добавлять created_at
и updated_at
как часть схемы, когда вы устанавливаете параметр timestamps как true.
Схема каталога
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;
Схема продукта
(Новая схема для обеспечения добавления 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;
РЕДАКТИРОВАТЬ (сохранять товары в каталоге)
(Также обратите внимание, что вам должен потребоваться модуль ProductSchema в вашем модуле CatalogueSchema)
// 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
});
Комментарии:
1. С помощью вашего метода я получаю [Product.schema] не определено.. Не могли бы вы, пожалуйста, показать мне, как бы вы сохранили модель ProductsSchema внутри CatalogueSchema?
2. Создавать отдельно
CatalogueSchema
иProductSchema
в отдельных модулях. Убедитесь, что вы импортировалиProductSchema
вCatalogueSchema
. Я добавил код для добавления продуктов в каталог.3. Вау, это действительно сработало. Огромное спасибо Сантану!
4. Рад, что смог помочь!
Ответ №2:
Чтобы добавить несколько документов в Mongo, вы можете использовать db.collection.insert()
:
В Mongoose вы можете использовать Model.insertMany()
:
Но имейте в виду, что когда у вас есть один документ внутри другого документа в Mongoose, они на самом деле хранятся не так, как в Mongo. Mongo хранит только идентификаторы дочерних документов, а не их содержимое в родительском документе — и даже никакой информации о том, к какой коллекции принадлежат эти идентификаторы.
Когда вы используете population, Mongoose фактически извлекает соответствующие документы из базы данных в отдельных запросах к Mongo. Итак, population — это концепция Mongoose. Mongo просто хранит идентификаторы, поэтому вам нужно сначала создать документы, прежде чем вы сможете вставить идентификаторы.
То, что вы пытаетесь сделать, было бы легко без использования Mongoose. Вы можете сохранить несколько документов в одном запросе в Mongo, используя свои собственные идентификаторы, если хотите, и вы можете сохранить другой документ с массивом этих идентификаторов в другом запросе.
Конечно, как бы вы это ни делали, вы получите несогласованное состояние во время операции, потому что Mongo не поддерживает транзакции.
Комментарии:
1. Я пробовал insertMany, но он не генерирует ObjectId. Если я попробую другим способом, сгенерировав продукты в другой схеме и используя .find для запроса к ним. В пакетном процессе это будет немного медленнее, чем иметь документ внутри другого документа?