NodeJS Mongo - Mongoose - 动态集合名称

Posted

技术标签:

【中文标题】NodeJS Mongo - Mongoose - 动态集合名称【英文标题】:NodeJS Mongo - Mongoose - Dynamic collection name 【发布时间】:2013-07-22 10:29:37 【问题描述】:

所以,我想创建一个基于客户端的分区模式,我将集合名称设置为 function(),我的伪代码是这样的:

var mongoose = require('mongoose'),
  Schema = mongoose.Schema,

var ConvForUserSchema = new Schema(
  user_id: Number,
  conv_hash: String,
  archived: Boolean,
  unread: Boolean
, function CollectionName() 
  return (this.user_id % 10000);
);

这是否可以通过 moongose 以任何方式实现,以使读写都按预期工作?

【问题讨论】:

【参考方案1】:
To Create a dynamic collection follow the below steps,

const mongoose = require('mongoose');
function createCompanyDynamicSchema(prefix) 
    let collectionName = prefix + '_company';
    companySchema = new mongoose.Schema(
        
            name:  type: String ,
            enabled:  type: Number, default: 1 ,
        ,
         timestamps: true ,
         versionKey: false ,
         strict: false 
    );
    collectionName = mongoose.model(collectionName, companySchema);
    return collectionName;


module.exports =  createCompanyDynamicSchema ;

To call this method from any file, 

let companySchema = require('./schema');

_this.createCompany = function () 
    return new Promise(async (resolve, reject) => 
        let companyCollection = companySchema.createCompanyDynamicSchema('IO');
        let addr = new companyCollection( first_name: 'test' );
        addr.save();
    );
;


To query from dynamically created collection,

_this.getCompany = function () 
    return new Promise(async (resolve, reject) => 
        let companyCollection = companySchema.createCompanyDynamicSchema('IO');
        let data = await companyCollection.model('IO_users').find();
        console.log(data);
    );
;

【讨论】:

【参考方案2】:

我正在添加 Javier Gomez 的答案,以解决 Exis Zang 的“OverwriteModelError:一旦编译后无法覆盖 xxx 模型”问题。 Schema 模型文件可以存储基于 Singleton 模式的动态模型数组。如果该模型已经存在,则返回它,否则使用 new 创建它,存储并返回它:

var mongoose  =  require('mongoose');
var Schema  =  mongoose.Schema;

const Addresses = 

// our schema 
function DynamicSchema(prefix)
    var addressSchema = new Schema(
        dir : type : String, required : true,    //los 2 nombres delimitados por coma (,) ej. Alberto,Andres
        city : type : String, required: true,   //la misma estructura que para los nombres ej. Acosta, Arteta 
        postal : type : Number, required : true,
        _home_type : type : Schema.Types.ObjectId, required : true, ref : prefix + '.home_type',
        state : type : String, required : true,
        telefono : String,
        registered : type : Date, default: Date.now 
    );
    return mongoose.model(prefix + '.address', addressSchema);


// this function will store the model in the Addresses object
// on subsequent calls, if it exists, it will return it from the array
function getAddressModel(prefix) 
  if (!Addresses[prefix]) 
    Addresses[prefix] =  new DynamicSchema(prefix)
  
  return Addresses[prefix]


//now we export getAddressModel function
module.exports = getAddressModel;

【讨论】:

【参考方案3】:

使用函数动态获取模型。

/* 
 * Define Schemas as you used to 
 */
const ConvForUserSchema = new Schema(
    user_id: Number,
    conv_hash: String,
    archived: Boolean,
    unread: Boolean
,
    versionKey : false,
    strict: false
);

/*
 * Define the dynamic function
 */
const models = ;
const getModel = (collectionName) => 
    if( !(collectionName in models) )
        models[collectionName] = connection.model(
            collectionName, ConvForUserSchema, collectionName
        );
    
    return models[collectionName];
;

然后使用函数得到动态模型

const result = getModel("YourCollectionName").findOne()

【讨论】:

【参考方案4】:

您好,您只需要使用您的动态名称声明模式模型,如下所示:

var mongoose  =  require('mongoose');
var Schema  =  mongoose.Schema;

// our schema 

function dynamicSchema(prefix)
    var addressSchema = new Schema(
        dir : type : String, required : true,    //los 2 nombres delimitados por coma (,) ej. Alberto,Andres
        city : type : String, required: true,   //la misma estructura que para los nombres ej. Acosta, Arteta 
        postal : type : Number, required : true,
        _home_type : type : Schema.Types.ObjectId, required : true, ref : prefix + '.home_type',
        state : type : String, required : true,
        telefono : String,
        registered : type : Date, default: Date.now 
    );
    return mongoose.model(prefix + '.address', addressSchema);


//no we export dynamicSchema function
module.exports = dynamicSchema;

所以在你的代码中任何你可以做到的地方:

var userAdress = require('address.js')(id_user);
var usrAdrs1 = new userAddress(...);
    userAdrs1.save();

现在转到您的 mongo shell 和列表集合(使用 mydb 然后显示集合),您将看到带有 uid 前缀的地址的新集合。这样mongoose会为每个不同的用户uid创建一个新的收集地址。

【讨论】:

我真的很喜欢这个解决方案,但我面临两种错误。首先,对于外键人口,似乎无法启动集合(因为 FK 被包裹在一个闭包中)而且OverwriteModelError: Cannot overwrite xxx model once compiled.【参考方案5】:

已实现:

//Require Mongoose
const mongoose = require('mongoose');
const moment = require('moment');

//Define a schema
const Schema = mongoose.Schema;

const EntranceModelSchema = new Schema(
    name: String,
    birthday: Date,
    gender: String,
    phoneNumber: type: String, require: true,
    email: String,
    address: String,
    addressReference: String,
    addressLatitude: type: Number, require: true,
    addressLongitude: type: Number, require: true,
    vehicleReference: String,
    date: Date
);

//Export function to create "SomeModel" model class
module.exports = function()
    let dateSuffix = moment().format('MMMDoYYYY');
    const collectionName = `Entrance$dateSuffix`;
    return mongoose.model(collectionName, EntranceModelSchema);
;

【讨论】:

【参考方案6】:

Gomosoft 的解决方案有效。它需要一些修改,但这个想法很有效。 上述解决方案仅在第一次时有效。如果您尝试向同一个集合发送第二个请求,它会因为尝试覆盖已定义的模型而引发错误。所以我不得不对其进行如下调整:

var Rating      = require('./app/models/rating');
var myRating;

router.route('/ratings/:user_id')
.post(function(req,res)

    var user_id         = req.params.user_id;
    if(myRating == undefined)
        myRating        = Rating(user_id);  
    

    ...

    rating.save(...);
);

因为我正在检查 myRating 是否未定义,所以它只会创建一次此引用。所以不会出现错误。 希望这会有所帮助。

【讨论】:

我认为这很难与 2 个单独的 user_id 一起使用。【参考方案7】:

集合名称逻辑在整个 Moongose 代码库中都进行了硬编码,因此无法按照现在的情况进行客户端分区。

我的解决方案是直接使用 mongo 驱动程序 -

https://github.com/mongodb/node-mongodb-native

事实证明这很好,直接与驱动程序合作的灵活性允许所有需要的东西,而且在任何情况下,Moongose 开销似乎都不会增加太多。

【讨论】:

以上是关于NodeJS Mongo - Mongoose - 动态集合名称的主要内容,如果未能解决你的问题,请参考以下文章

通过Mongoose(Node JS)在Mongo DB中插入没有JSON模式的JSON对象

使用 geojson 和 mongoose 将多边形坐标插入 Mongo DB 时出错

Mongo/Mongoose 快速更新导致数据丢失

Mongo/Mongoose 中的复杂约束

如何更新nodejs中的mongo嵌套数组?

NodeJS + Express + Mongo Session 存储