gpt4 book ai didi

javascript - 附加在无模式数组内部

转载 作者:太空宇宙 更新时间:2023-11-04 00:59:27 25 4
gpt4 key购买 nike

我是MongoDB的新手,到目前为止遇到了问题,在这里我很难在Schema-Less Array中附加多个对象,到目前为止,我尝试$ push在array中附加多个对象,但是遇到Mongo错误。

[MongoError: Can't use $push/$pushALL within non-array


当将$ push与array一起使用时,我不知道为什么会收到此错误

架构:

EventTypeSchema = new Schema(){
type: String,
eventID: {
type: Schema.Types.ObjectId,
ref: 'User'
}
}

PersonSchema = new Schema(){
PersonID: {
type: Schema.Types.ObjectId,
ref: 'User'
}
Invitation: [ ] //Schema-less
}


在Controller中,我可以访问EventType和Person模型
控制器:

exports.update = function(req,res){
var event = new EventType();
event.type = 'EVENT';
event.eventID = req.body.eventid;
var query = {'PersonID': req.body.personid};
var update = {$push:{'Invitation': event}};
Person.update(query,update,function(err,user){...})
};


出于调试目的,我尝试为数组提供混合类型架构,但没有使其正常工作

PersonSchema = new Schema(){
PersonID: {
type: Schema.Types.ObjectId,
ref: 'User'
}
Invitation: [ {
type: Schema.Types.Mixed
} ]
}


当我在更新中删除$ push时,只有整个事件对象都进入了邀请函,我之所以创建无架构数组是因为我正在处理不同类型的邀请函,这里我只是描述了事件邀请函,否则有不同类型的我正在处理的邀请,例如用户邀请,会议邀请,因此将不同objectId组合在一起,我认为应该有一种方法可以附加到mongoDB中的无模式数组。

编辑:

以下是我想出的。虽然无法使其正常工作。

function PortalTypes() {
Schema.apply(this,arguments);
this.add({
object_type: String,
});
}

util.inherits( PortalTypes, Schema );

var userType = new PortalTypes({
ID : {
type: Schema.Types.ObjectId,
ref : 'User'
}
});

var eventType = new PortalTypes({
ID : {
type: Schema.Types.ObjectId,
ref : 'events'
}
});



var user = new userType({ID:'dsaj3232--objectID','object_type':'user'});
user.save();

var event = new eventType({ID:'dasddehiqe98--objectID','object_type':'event'});
event.save();

Networks.Invitation.push(user,event);


我该怎么做?

最佳答案

尽管您的模式是错误的,但最上面的错误表示该集合中有一个匹配的文档,该文档没有将此字段设置为数组,但是存在另一种类型。可能只是一个字符串或对象。

这是一个简短的示例清单,用于演示:

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

var personSchema = new Schema({
invitation: []
});

var Person = mongoose.model( 'Person', personSchema );

mongoose.connect('mongodb://localhost/test');

async.waterfall(
[
function(callback) {
Person.remove({},function(err,num) {
callback(err);
});
},

function(callback) {
console.log( "Creating" );
var person = new Person();
person.save(function(err,person) {
if (err) callback(err);
console.log(person);
callback(err,person);
});
},

function(person,callback) {
console.log( "Updating" );
Person.findOneAndUpdate(
{ "_id": person._id },
{ "$push": { "invitation": "something" } },
function(err,doc) {
if (err) callback(err);
console.log(doc);
callback(err);
}
);
},

function(callback) {
console.log( "Upserting" );
Person.findOneAndUpdate(
{ "name": "bob" },
{ "$set": { "invitation": {} } },
{ "upsert": true },
function(err,doc) {
if(err) callback(err);
console.log(doc);
callback(err,doc);
}
);
},

function(bob,callback) {
console.log( "Failing" );
Person.findOneAndUpdate(
{ "name": "bob" },
{ "$push": { "invitation": "else" } },
function(err,doc) {
if (err) callback(err);
console.log(doc);
callback(err);
}
);
}

],
function(err) {
if (err) throw err;
console.log( "Done" );
mongoose.disconnect();

}
);


那应该给出如下结果:

Creating
{ __v: 0, _id: 54a18afb345b4efc02f21020, invitation: [] }
Updating
{ _id: 54a18afb345b4efc02f21020,
__v: 0,
invitation: [ 'something' ] }
Upserting
{ _id: 54a18afb9997ca0c4a7eb722,
name: 'bob',
__v: 0,
invitation: [ {} ] }
Failing

/home/neillunn/scratch/persons/node_modules/mongoose/lib/utils.js:413
throw err;
^
MongoError: exception: The field 'invitation' must be an array but is of type Object
in document {_id: ObjectId('54a18afb9997ca0c4a7eb722')}


错误消息有所不同,因为在MongoDB 2.6及更高版本(此错误字符串来自)中进行了一些改进,以使有关实际问题的准确性更高。因此,在现代版本中,您会确切地知道出了什么问题。

尽管有模式,但 .update()之类的方法(为方便起见,我使用 .findOneAndUpdate())会略过猫鼬模式的定义并直接进入数据库。因此,可以执行此操作,也可以仅在适当的位置放置一个文档,或者在不同的架构定义存在时创建一个文档。

所以这是第一个问题。



您似乎要问的其余问题是数组中的“多态”关联类型,以及您不希望将整个创建的对象“嵌入”到数组中,而只是对其的引用。

猫鼬具有 "discriminators"来允许这种事情,允许将对象的不同模型类型存储在同一集合中,但解析为它们自己的对象和模式“类型”。

在当前文档示例之后,以下是示例列表,该列表可能看起来像:

var util = require('util'),
async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;

function logger(label,content) {
console.log(
"%s:\n%s\n", label, JSON.stringify( content, undefined, 4 ) );
}

function BaseSchema() {

Schema.apply(this,arguments);

this.add({
name: String,
createdAt: { type: Date, default: Date.now }
});

}

util.inherits( BaseSchema, Schema );


var personSchema = new BaseSchema(),
bossSchema = new BaseSchema({ department: String });

var companySchema = new Schema({
people: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});


var Person = mongoose.model( 'Person', personSchema ),
Boss = Person.discriminator( 'Boss', bossSchema ),
Company = mongoose.model( 'Company', companySchema );

mongoose.connect('mongodb://localhost/test');

async.waterfall(
[
function(callback) {
Company.remove({},function(err,num) {
callback(err);
});
},
function(callback) {
Person.remove({},function(err,num) {
callback(err);
});
},
function(callback) {
var person = new Person({ name: "Bob" });
person.save(function(err,person) {
logger("Person", person);
callback(err,person);
});
},
function(person,callback) {
var boss = new Boss({ name: "Ted", department: "Accounts" });
boss.save(function(err,boss) {
logger("Boss", boss);
callback(err,person,boss);
});
},
function(person,boss,callback) {
var company = new Company();
company.people.push(person,boss);
company.save(function(err,company) {
logger("Stored",company);
callback(err,company);
});
},
function(company,callback) {
Company.findById(company.id)
.populate('people')
.exec(function(err,company) {
logger("Polulated",company);
callback(err);
});
}
],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
);


将产生如下输出:

Person:
{
"__v": 0,
"name": "Bob",
"createdAt": "2014-12-29T17:53:22.418Z",
"_id": "54a1951210a7a1b603161119"
}

Boss:
{
"__v": 0,
"name": "Ted",
"department": "Accounts",
"__t": "Boss",
"createdAt": "2014-12-29T17:53:22.439Z",
"_id": "54a1951210a7a1b60316111a"
}

Stored:
{
"__v": 0,
"_id": "54a1951210a7a1b60316111b",
"people": [
"54a1951210a7a1b603161119",
"54a1951210a7a1b60316111a"
]
}

Polulated:
{
"_id": "54a1951210a7a1b60316111b",
"__v": 0,
"people": [
{
"_id": "54a1951210a7a1b603161119",
"name": "Bob",
"__v": 0,
"createdAt": "2014-12-29T17:53:22.418Z"
},
{
"_id": "54a1951210a7a1b60316111a",
"name": "Ted",
"department": "Accounts",
"__v": 0,
"__t": "Boss",
"createdAt": "2014-12-29T17:53:22.439Z"
}
]
}


如您所见,保存 PersonBoss的方式存在不同的结构,尤其是 _t属性以及为不同对象定义的其他属性。但是,两者实际上都存储在相同的“人员”集合中,因此可以查询。

当将它们存储在 Company对象上时,只有“参考ID”值存储在数组中。可能与您想要的内容有争议,但这是“引用”和“嵌入式”架构模型之间的区别。但是,您可以看到在调用 .populate()方法时,当从引用的集合中读取对象时,这些对象将还原为完整格式。



因此,请检查您的集合中是否存在与架构定义不同的现有文档,并考虑所显示的方法来表示对象的不同“类型”的“多态”关联。

请注意,尽管这种分辨率仅在“引用”模式设计下受支持,但也可能有其缺点。如果您希望将对象存储为“嵌入”在单个 Company集合中(例如),则不会获得由猫鼬自动完成的具有不同模式类型的对象解析类型。解决不同类型的对象必须在您的代码中手动完成,或者在提供的插件中完成,但是您可以这样做。

更多

针对所有目的,因为在基于标准文档示例的内容之后似乎有些混乱,所以下面是一个注释较多的清单:

var util = require('util'),
async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;

// Utility
function logger(label,content) {
console.log(
"%s:\n%s\n", label,
util.inspect( content, false, 8, false ) );
}

/*
* Schemas:
*
* you can use a base schema for common fields or just a plain
* definition
*/

var portalSchema = new Schema(),

userSchema = new Schema({
"name": String,
"age": Number
}),

eventSchema = new Schema({
"place": String,
"eventDate": { type: Date, default: Date.now }
});

/*
* Models
*
* there is only one "model" defined and therefore one collection only
* as everything is comes from a stored __v field with the "Model" name
* defined in the discriminator
*/

var Portal = mongoose.model( 'Portal', portalSchema ),
User = Portal.discriminator( 'User', userSchema ),
Event = Portal.discriminator( 'Event', eventSchema );

/*
* Then there is the thing that is going to consume the references to the
* 'Portal' model. The array here references the "base" model.
*/

var otherSchema = new Schema({
"afield": String,
"portals": [{ type: Schema.Types.ObjectId, ref: "Portal" }]
});

var Other = mongoose.model( 'Other', otherSchema );

/*
* Meat:
*
* Let's start doing things
*/

mongoose.connect('mongodb://localhost/test');

// Just because we're passing around objects without globals or other scoping
async.waterfall(
[
// Start fresh by removing all objects in the collections
function(callback) {
Other.remove({},function(err,num) {
callback(err);
});
},
function(callback) {
Portal.remove({},function(err,num) {
callback(err);
});
},

// Create some portal things
function(callback) {
var eventObj = new Event({ "place": "here" });
eventObj.save(function(err,eventObj) {
logger("Event", eventObj);
callback(err,eventObj);
});
},
function(eventObj,callback) {
var userObj = new User({ "name": "bob" });
userObj.save(function(err,userObj) {
logger("User", userObj);
callback(err,eventObj,userObj);
});
},

// Store the references in the array for the Other model
function(eventObj,userObj,callback) {
var other = new Other({
"afield": "something"
});
other.portals.push(eventObj,userObj);
other.save(function(err,other) {
logger("Other Stored",other);
callback(err,other);
});
},

// See how it's all really stored
function(other,callback) {
Portal.find({},function(err,portals) {
logger("Portals",portals);
callback(err,other);
});
},

// But watch the magic here
function(other,callback) {
User.find({},function(err,portals) {
logger("Just Users!",portals);
callback(err,other);
});
},


// And constructed as one object by populate
function(other,callback) {
Other.findById(other.id)
.populate('portals')
.exec(function(err,other) {
logger("Other populated",other);
console.log("%s: %s",
"1st Element", other.portals[0].constructor.modelName );
console.log("%s: %s",
"2nd Element", other.portals[1].constructor.modelName );

callback(err);
});
}

],
function(err) {
// It's just a script, so clean up
if (err) throw err;
mongoose.disconnect();
}
);


那应该解释一些事情以及什么是“歧视者”。一切都存储在绑定到基础模型的“一个”集合中。其他所有内容均使用该库中的 .discriminator()定义。 “类模型”或“鉴别器”的“名称”存储在对象上。但是请注意,它仅存储在集合中,而不是在引用它们的地方存储,因为它仅存储 _id值。仔细看一下输出:

Event:
{ __v: 0,
place: 'here',
__t: 'Event',
_id: 54a253ec456b169310d131f9,
eventDate: Tue Dec 30 2014 18:27:40 GMT+1100 (AEDT) }

User:
{ __v: 0,
name: 'bob',
__t: 'User',
_id: 54a253ec456b169310d131fa }

Other Stored:
{ __v: 0,
afield: 'something',
_id: 54a253ec456b169310d131fb,
portals: [ 54a253ec456b169310d131f9, 54a253ec456b169310d131fa ] }

Portals:
[ { _id: 54a253ec456b169310d131f9,
place: 'here',
__v: 0,
__t: 'Event',
eventDate: Tue Dec 30 2014 18:27:40 GMT+1100 (AEDT) },
{ _id: 54a253ec456b169310d131fa,
name: 'bob',
__v: 0,
__t: 'User' } ]

Just Users!:
[ { _id: 54a253ec456b169310d131fa,
name: 'bob',
__v: 0,
__t: 'User' } ]

Other populated:
{ _id: 54a253ec456b169310d131fb,
afield: 'something',
__v: 0,
portals:
[ { _id: 54a253ec456b169310d131f9,
place: 'here',
__v: 0,
__t: 'Event',
eventDate: Tue Dec 30 2014 18:27:40 GMT+1100 (AEDT) },
{ _id: 54a253ec456b169310d131fa,
name: 'bob',
__v: 0,
__t: 'User' } ] }

1st Element: Event
2nd Element: User


因此,所有“门户”类型只有一个集合,但是有一些魔术,如图所示。 “其他”集合仅将 _id值存储在其“门户”数组中。这是猫鼬引用的工作方式,其中“模型”和附加模式未存储在数据中,而是作为代码定义的一部分存储。

“区分符”部分将这个“模型名称”存储在字段上,以便可以将其解析为正确的类型,但是仍然全部在同一集合中,并且展示了 User模型魔术的一部分。

为什么?这就是 .populate()的工作方式。在幕后,将 $in运算符与数组内容一起使用,因此它们都应该放在一个位置。但是您仍然可以如图所示解析类型。

如果希望使用单独的集合,那么您将自己做所有事情,并存储模型名称,并自行查询其他集合以获取引用。

关于javascript - 附加在无模式数组内部,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27693904/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com