我正在使用ExtJS + mongoDB来实现一个应用程序。我使用node.js作为服务器和express模块来创建REST api。 详细地说,我使用:ExtJS 4.1.3 + mongoose 1.2.17 + express 1.2.17 + mongodb 2.4,在Node.js v0.10.3上运行。
代码ExtJS部分(在MVC中组织):
Model部分包含两个模型,PvdcPrice和PvdcPriceDetails,它们有" hasMany"关系。
PvdcPrice.js:
Ext.define('App.model.PvdcPrice', {
extend : 'Ext.data.Model',
fields : [{
name : '_id',
type : 'Number'
}, {
name : 'Type',
type : 'string'
}, {
name : 'MaxDiscount',
type : 'Number'
}],
hasMany : [{
name : 'prices',
model : 'App.model.PvdcPriceDetail',
associationKey : 'prices'
}],
proxy : {
type : 'rest',
url : '/pvdcprices',
reader : {
type : 'json',
root : 'data',
successProperty : 'success'
}
}
});
PvdcPriceDetail.js:
Ext.define('App.model.PvdcPriceDetail', {
extend : 'Ext.data.Model',
fields : [{
name : 'ID',
type : 'Number'
}, {
name : 'Location',
type : 'string'
}, {
name : 'Edition',
type : 'string'
}, {
name : 'MonthlyPrice',
type : 'Number'
}, {
name : 'OneTimePrice',
type : 'Number'
}
]
});
控制器部分,因为它太长了我只把商店创建部分放在这里:
var pvdcPrice = Ext.create('Ext.data.Store', {
model : "App.model.PvdcPrice",
data : [{
"_id" : 1,
"Type" : "pvdc",
"MaxDiscount" : "0"
}]
});
var priceInfo = pvdcPrice.first();
var pvdcPriceDetails = priceInfo.prices();
pvdcPriceDetails.add({
'ID' : 1,
'Location' : 'SNJ',
'Edition' : 'Basic',
'MonthlyPrice' : 906,
'OneTimePrice' : 777
});
pvdcPriceDetails.add({
'ID' : 2,
'Location' : 'ATL',
'Edition' : 'Standard',
'MonthlyPrice' : 906,
'OneTimePrice' : 777
});
pvdcPriceDetails.add({
'ID' : 3,
'Location' : 'ATL',
'Edition' : 'Standard',
'MonthlyPrice' : 906,
'OneTimePrice' : 777
});
pvdcPrice.sync();
var record = pvdcPrice.first();
console.log(record.get('Type'));
record.prices().each(function(r) {
console.log(r.get('Location'));
console.log(r.get('Edition'));
});
Node.js部分,服务器脚本是app.js:
var express = require('express'),
app = module.exports = express();
// MongoDB
var mongoose = require('mongoose'),
db = mongoose.connect('mongodb://127.0.0.1/IaaSDB'),
//create sub schema of pvdc price schema
PriceDetailSchema = new mongoose.Schema({
ID: Number,
Location: String,
Edition: String,
MonthlyPrice: Number,
OneTimePrice: Number
}),
//create the Pvdc price info Model using the 'pvdcPrice' collection as a data-source
PvdcPrice = mongoose.model('pvdcPrice', new mongoose.Schema({
Type: String,
MaxDiscount: String,
prices: [PriceDetailSchema]
}));
// Configuration
app.configure(function () {
//app.set('views', __dirname + '/views');
//app.set('view engine', 'jade');
app.use(express.bodyParser());//parse JSON into objects
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/IaaSPriceTool'));
});
app.configure('development', function () {
app.use(express.errorHandler({
dumpExceptions: true,
showStack: true
}));
});
app.configure('production', function () {
app.use(express.errorHandler());
});
// Routes
app.get('/', function (req, res) {
res.redirect('/index.html');
});
/*
Pvdc Price Information CRUD web service
*/
app.get('/pvdcprices', function (req, res) {
PvdcPrice.find({}, function (err, pvdcprices) {
res.contentType('json');
res.json({
success: true,
data: pvdcprices
});
});
});
app.get('/pvdcprices/:id', function(req, res){
PvdcPrice.find({_id: req.params.id}, function (err, pvdcPrices) {
res.contentType('json');
res.json({
success: true,
data: pvdcPrices
});
});
});
app.post('/pvdcprices', function (req, res) {
console.log("[200] " + req.method + " to " + req.url);
console.log(req.body);
var newPriceInfo = new PvdcPrice();
var newPriceInfoData = req.body;
//remove the id which the client sends since it is a new pvdc price
delete newPriceInfo['_id'];
newPriceInfo.set(newPriceInfoData);
newPriceInfo.save(function (err, pvdcPrice) {
res.contentType('json');
res.json({
success: !err,
data: pvdcPrice
});
});
});
app.listen(3000);
console.log("Express server listening on port %d in %s mode", 3000, app.settings.env);
之后,我使用firebug来调试前端,我可以从浏览器控制台看到pvdc价格的竞争显示:
POST http://localhost:3000/pvdcprices?_dc=1369740182183 200 OK 27ms
pvdc
Basic
ATL
Standard
ATL
Standard
这意味着ExtJS中的关联模型有效,我可以看到pvdcPrice的内容。 ExtJS中的json结构应该是:
{
"data" :{
"_id" : 1,
"Type" : "pvdc",
"MaxDiscount" : "0",
"prices" : [{
'ID' : 1,
'Location' : 'SNJ',
'Edition' : 'Basic',
'MonthlyPrice' : 906,
'OneTimePrice' : 777
},{
'ID' : 2,
'Location' : 'ATL',
'Edition' : 'Standard',
'MonthlyPrice' : 906,
'OneTimePrice' : 777
},{
'ID' : 3,
'Location' : 'ATL',
'Edition' : 'Standard',
'MonthlyPrice' : 906,
'OneTimePrice' : 777
}]
}
}
但是来自node.js的响应是成功的:false。
然后在node.js部分的控制台中,我在node.js中打印post的请求体,它是:
[200] POST to /pvdcprices?_dc=1369734975208
{ _id: 1, Type: 'pvdc', MaxDiscount: 0, id: null }
"价格"的子内容缺少,只有pvdcPrice的主要部分发布到服务器。
有人可以指出在后期处理中导致失踪的原因吗? 真的很感激帮助:)
答案 0 :(得分:1)
最后解决了这个问题,关键是ExtJS 4中的Ext.data.writer.Json不支持关联。
此链接提供了一些解决方案。
我使用Extjs 4.1.1 a,并将DeepJson添加到Extjs 4.1源文件夹中:
/**
* @class Ext.data.writer.DeepJson This class is used to write
* {@link Ext.data.Model} data to the server in a JSON format.
*
* It overrides the original Ext.data.writer.Json since the Json can not handle
* hasMany association, it can only transform the outside part into Json, the
* inside data will be omiited.
*
* @Yi Fang Reference:
* http://www.sencha.com/forum/showthread.php?141957-Saving-objects-that-are-linked-hasMany-relation-with-a-single-Store/page3 23 Mar 2012 6:00 AM
* http://www.sencha.com/forum/showthread.php?141957-Saving-objects-that-are-linked-hasMany-relation-with-a-single-Store/page5 13 Feb 2013 2:57 PM
*
*/
Ext.define('Ext.data.writer.DeepJson', {
extend : 'Ext.data.writer.Json',
getRecordData : function(record, operation) {
// Setup variables
var me = this, i, association, childStore, data;
data = me.callParent(arguments);
// Iterate over all the hasMany associations
for (i = 0; i < record.associations.length; i++) {
association = record.associations.get(i);
if (association.type == 'hasMany') {
data[association.name] = null;
childStore = record[association.storeName];
// Iterate over all the children in the current
// association
childStore.each(function(childRecord) {
if (!data[association.name]) {
data[association.name] = [];
}
// Recursively get the record data for
// children (depth first)
var childData = this.getRecordData.call(
this, childRecord);
/*
* If the child was marked dirty or phantom
* it must be added. If there was data
* returned that was neither dirty or
* phantom, this means that the depth first
* recursion has detected that it has a
* child which is either dirty or phantom.
* For this child to be put into the
* prepared data, it's parents must be in
* place whether they were modified or not.
*/
if (childRecord.dirty
|| childRecord.phantom
|| (childData != null)) {
data[association.name].push(childData);
record.setDirty();
}
}, me);
/*
* Iterate over all the removed records and add them to
* the preparedData. Set a flag on them to show that
* they are to be deleted
*/
Ext.each(childStore.removed, function(
removedChildRecord) {
// Set a flag here to identify removed
// records
removedChildRecord.set('forDeletion', true);
var removedChildData = this.getRecordData
.call(this, removedChildRecord);
data[association.name]
.push(removedChildData);
record.setDirty();
}, me);
}
}
// Only return data if it was dirty, new or marked for deletion.
if (record.dirty || record.phantom || record.get('forDeletion')) {
return data;
}
return null;
}
});
在PvdcPrice模型中,将代理更新为
proxy : {
type : 'rest',
url : '/pvdcprices',
reader : {
type : 'json',
root : 'data',
successProperty : 'success'
},
writer : Ext.create('Ext.data.writer.DeepJson')
}
然后嵌套数据的帖子工作。
答案 1 :(得分:0)
belongsTo: 'App.model.PvdcPrice'
模型类中缺少 'App.model.PvdcPriceDetail'
。它是代码中的关联问题,您需要使用子模型映射父类键。请参考以下链接(在协会会议中)。
http://docs.sencha.com/extjs/4.2.0/#!/guide/data
我希望在将您的belongsTo配置设置为“App.model.PvdcPriceDetail”类后,它将按预期正常工作。
由于