【问题标题】:Mongoose - Generate ObjectID for each object before saving documentMongoose - 在保存文档之前为每个对象生成 ObjectID
【发布时间】:2026-02-07 03:45:01
【问题描述】:

我想为数组中存在的每个对象生成一个 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")
}

有什么方法可以做到这一点而不必进行大量的数据库调用?我无法想象像这样保存

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

希望有人已经研究过类似的东西并找到了完美的解决方案!

【问题讨论】:

    标签: javascript node.js mongoose mongoose-schema objectid


    【解决方案1】:

    要将多个文档添加到 Mongo 中,您可以使用 db.collection.insert():

    在 Mongoose 中,您可以使用 Model.insertMany():

    但请记住,当您在 Mongoose 中的另一个文档中包含一个文档时,它们实际上并没有像 Mongo 中那样存储。 Mongo 只存储子文档的 ID,而不是它们在父文档中的内容 - 甚至没有关于这些 ID 属于哪个集合的任何信息。

    当您使用人口时,Mongoose 实际上会在对 Mongo 的单独请求中从数据库中检索相关文档。所以,人口是猫鼬的一个概念。 Mongo 只存储 ID,因此您需要先创建文档,然后才能插入 ID。

    如果不使用 Mongoose,您尝试做的事情会很容易。如果需要,您可以使用自己的 ID 在 Mongo 的一个请求中存储多个文档,并且可以在另一个请求中存储具有这些 ID 数组的另一个文档。

    当然,无论如何你都会在操作过程中得到不一致的状态,因为 Mongo 不支持事务。

    【讨论】:

    • 我尝试了 insertMany,但它没有生成 ObjectID。如果我以另一种方式尝试通过在不同的架构中生成产品并使用 .find 来查询它们。在批处理过程中,这会比在另一个文档中包含一个文档要慢一些吗?
    【解决方案2】:

    如果要自动添加ObjectId,则需要为其定义单独的架构,并将架构的_id选项设置为true。

    执行以下操作:

    • 将您的 productsSchema 更改为 CatalogueSchema(为了便于 理解)。
    • 为 Product(allProducts 的元素)定义一个新的 ProductSchema
    • CatalogueSchema 中将所有产品类型定义为[Product.schema]。这将自动添加_id (ObjectId)。

    此外,当您将时间戳选项设置为 true 时,您不需要添加 created_atupdated_at 作为架构的一部分。

    目录架构

    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;
    

    编辑将产品保存在目录中

    (另外,请注意,您必须在 CatalogueSchema 模块中要求 ProductSchema 模块)

    // 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
    });
    

    【讨论】:

    • 用你的方法我得到 [Product.schema] 是未定义的。你能告诉我你如何将 ProductsSchema 模型保存在 CatalogueSchema 中吗?
    • 在单独的模块中创建单独的 CatalogueSchemaProductSchema。确保将ProductSchema 导入CatalogueSchema。我已经添加了将产品添加到目录的代码。
    • 哇,这确实有效。非常感谢桑塔努!
    • 很高兴能帮上忙!
    最近更新 更多