대답의 동일한 줄을 따라 가면서 펀치를 때리면 나에게 설명이 더 오래 걸렸으므로 시간이 좀 걸립니다.
한가지 더 조정하면 매우 똑같습니다. 균형에 $inc
연산자를 사용하여 트랜잭션을 수행하면, 오히려 재 계산보다는 코드 때문에 기본적으로이 블록을 원하는 것입니다 :
bucket.find({
"account": accId, "owner": owner, "day": day
}).upsert().updateOne(
{
"$inc": { "balance": amount },
"$push": {
"transactions": {
"$each": [{ "amount": amount, "added": date }],
"$sort": { "added": -1 }
}
}
}
);
다른 부분은 버킷 개념이다 "조정할". 기본적으로 배열을 사용하여이 작업을 수행하는 것이 좋은 생각이며 $inc
을 사용하면 트랜잭션의 해당 부분이 원 자성이되며 문제는 배열에 많은 항목을 원하지 않는다는 것입니다. 그리고 이것은 시간이 지남에 따라 상당히 증가 할 것입니다.
이 작업을 수행하는 가장 좋은 방법은 해당 배열에 너무 많은 항목을 보관하고 이들을 "양동이"결과로 제한하는 것입니다. 단 하나의 "균형"지점을 동기화 상태로 유지하려는 "시도"를 위해 여기에 좀 더 많은 처리 기능을 추가했습니다. 실제로는 결과적으로 여러 업데이트가 트랜잭션에 바인딩되지 않으므로 주기적으로 확인하려고합니다. .
하지만 "버킷"에 대한 업데이트는 원상태입니다. 마일리지는 실제 구현에 따라 달라질 수 있지만, 여기에 essentinal 데모 코드 :
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/shop');
var ownerSchema = new Schema({
name: String,
email: String,
accounts: [{ type: Schema.Types.ObjectId, ref: "Account" }]
});
var transactionSchema = new Schema({
amount: Number,
added: Date
});
var recentBucketSchema = new Schema({
_id: { type: Schema.Types.ObjectId, ref: "AccountBucket" },
day: Date
});
var accountSchema = new Schema({
owner: { type: Schema.Types.ObjectId, ref: "Owner" },
balance: { type: Number, default: 0 },
recent: [recentBucketSchema]
});
var accountBucketSchema = new Schema({
day: Date,
account: { type: Schema.Types.ObjectId, ref: "Account" },
owner: { type: Schema.Types.ObjectId, ref: "Owner" },
balance: { type: Number, default: 0 },
transactions: [transactionSchema]
});
var Owner = mongoose.model("Owner", ownerSchema);
var Account = mongoose.model("Account", accountSchema);
var AccountBucket = mongoose.model("AccountBucket", accountBucketSchema);
var owner = new Owner({ name: "bill", emal: "[email protected]" });
var account = new Account({ owner: owner });
owner.accounts.push(account);
var transact = function(accId,owner,amount,date,callback) {
var day = new Date(
date.valueOf() - (date.valueOf() % (1000 * 60 * 60 * 24)));
var bucket = AccountBucket.collection.initializeOrderedBulkOp();
var account = Account.collection.initializeOrderedBulkOp();
bucket.find({
"account": accId, "owner": owner, "day": day
}).upsert().updateOne(
{
"$inc": { "balance": amount },
"$push": {
"transactions": {
"$each": [{ "amount": amount, "added": date }],
"$sort": { "added": -1 }
}
}
}
);
bucket.execute(function(err,response) {
if (err) throw err;
var upObj = {
"$inc": { "balance": amount }
};
if (response.nUpserted > 0) {
var id = response.getUpsertedIds()[0]._id;
upObj["$push"] = {
"recent": {
"$each": [{ "_id": id, "day": day }],
"$sort": { "day": -1 },
"$slice": 30
}
};
}
console.log(JSON.stringify(upObj, undefined, 4));
account.find({ "_id": accId }).updateOne(upObj);
account.execute(function(err,response) {
callback(err,response);
});
}
);
};
mongoose.connection.on("open",function(err,conn) {
async.series([
function(callback) {
async.each([Owner,Account,AccountBucket],function(model,complete) {
model.remove(function(err) {
if (err) throw err;
complete();
});
},function(err) {
if (err) throw err;
callback();
});
},
function(callback) {
async.each([account,owner],function(model,complete) {
model.save(function(err) {
if (err) throw err;
complete();
});
},function(err) {
if (err) throw err;
callback();
});
},
function(callback) {
var trandate = new Date();
transact(account._id,owner._id,10,trandate,function(err,response) {
if (err) throw err;
console.log(JSON.stringify(response, undefined, 4));
callback();
});
},
function(callback) {
var trandate = new Date();
trandate = new Date(trandate.valueOf() + (1000 * 60 * 60 * 1));
transact(account._id,owner._id,-5,trandate,function(err,response) {
if (err) throw err;
console.log(JSON.stringify(response, undefined, 4));
callback();
});
},
function(callback) {
var trandate = new Date();
trandate = new Date(trandate.valueOf() - (1000 * 60 * 60 * 1));
transact(account._id,owner._id,15,trandate,function(err,response) {
if (err) throw err;
console.log(JSON.stringify(response, undefined, 4));
callback();
});
},
function(callback) {
var trandate = new Date();
trandate = new Date(trandate.valueOf() - (1000 * 60 * 60 * 24));
transact(account._id,owner._id,-5,trandate,function(err,response) {
if (err) throw err;
console.log(JSON.stringify(response, undefined, 4));
callback();
});
},
function(callback) {
var trandate = new Date("2014-07-02");
transact(account._id,owner._id,10,trandate,function(err,response) {
if (err) throw err;
console.log(JSON.stringify(response, undefined, 4));
callback();
});
},
],function(err) {
String.prototype.repeat = function(num) {
return new Array(num + 1).join(this);
};
console.log("Outputs\n%s\n", "=".repeat(80));
async.series([
function(callback) {
Account.findById(account._id,function(err,account) {
if (err) throw err;
console.log(
"Raw Account\n%s\n%s\n",
"=".repeat(80),
JSON.stringify(account, undefined, 4)
);
callback();
});
},
function(callback) {
AccountBucket.find({},function(err,buckets) {
if (err) throw err;
console.log(
"Buckets\n%s\n%s\n",
"=".repeat(80),
JSON.stringify(buckets, undefined, 4)
);
callback();
});
},
function(callback) {
Account.findById(account._id)
.populate("owner recent._id")
.exec(function(err,account) {
if (err) throw err;
var raw = account.toObject();
raw.transactions = [];
raw.recent.forEach(function(recent) {
recent._id.transactions.forEach(function(transaction) {
raw.transactions.push(transaction);
});
});
delete raw.recent;
console.log(
"Merged Pretty\n%s\n%s\n",
"=".repeat(80),
JSON.stringify(raw, undefined, 4)
);
callback();
});
}
],function(err) {
process.exit();
});
});
});
이 목록은 MongoDB를 2.6에서 사용할 수있는 "대량"업데이트 API 기능을 사용하고 있습니다,하지만 당신은 그것을 사용할 필요가 없습니다.업데이트에서 더 의미있는 응답을 버리는 것은 여기에 있습니다.
트랜잭션을 "버킷으로 넣기"하는 일반적인 경우는 어떻게 든 분할하는 것입니다. 여기의 기본 예제는 "day"이지만, 아마도 다른 것이 더 실용적 일 수 있습니다.
해당 식별자가 변경 될 때 새 버킷을 만들 수 있도록 MongoDB 업데이트의 "upsert"기능이 사용됩니다. 나중에 모든 버킷에서 균형을 유지할 수 있기 때문에 일반적으로 괜찮을 것입니다.하지만이 경우에는 "계정"마스터를 동기화하려고 적어도 시도 할 것입니다. 데모.
현재 버킷에 대한 업데이트가 완료된 후 응답이 검사되어 "업서 트"가 발생했는지 확인합니다. 기존 또는 몽구스 API .update()
에서는 콜백의 세 번째 인수에 "upserted"문서의 _id
을 반환합니다.
"upsert"가 발생하고 새 버킷이 생성되는 경우이를 최근 버킷 목록, 실제로 가장 최근 30 개의 버킷 목록으로 마스터 "Account"에 추가합니다. 따라서 이번에는 $push
작업은 다른 수정자를 다른 $each
및 $sort
작업에 추가로 사용합니다.
마지막 두 개는 추가 할 배열 요소가 하나만 있어도 함께 사용해야합니다. MongoDB 2.4 버전에서는 실제로이 수정 자와 함께 $slice
이 항상 필요하므로 제한하지 않으려면 $slice
을 큰 수로 설정하십시오. 그러나 배열 길이를 제한하는 것이 좋습니다.
모든 경우에 모든 샘플 코드가 삽입되는 순서에도 불구하고 가장 최근 날짜순으로 날짜가 정렬됩니다. 출력은이 형식으로 실제로 쓰기 작업에서 발생하는 모든 것을 보여 주지만 일반적인 최종 결과의 요약은 여기에 있습니다.
Outputs
========================================================================
Raw Account
========================================================================
{
"_id": "53bf504ac0716cbc113fbac5",
"owner": "53bf504ac0716cbc113fbac4",
"__v": 0,
"recent": [
{
"_id": "53bf504a79b21601f0c00d1d",
"day": "2014-07-11T00:00:00.000Z"
},
{
"_id": "53bf504a79b21601f0c00d1e",
"day": "2014-07-10T00:00:00.000Z"
},
{
"_id": "53bf504a79b21601f0c00d1f",
"day": "2014-07-02T00:00:00.000Z"
}
],
"balance": 25
}
Buckets
========================================================================
[
{
"_id": "53bf504a79b21601f0c00d1d",
"account": "53bf504ac0716cbc113fbac5",
"day": "2014-07-11T00:00:00.000Z",
"owner": "53bf504ac0716cbc113fbac4",
"transactions": [
{
"amount": -5,
"added": "2014-07-11T03:47:38.170Z"
},
{
"amount": 10,
"added": "2014-07-11T02:47:38.153Z"
},
{
"amount": 15,
"added": "2014-07-11T01:47:38.176Z"
}
],
"balance": 20
},
{
"_id": "53bf504a79b21601f0c00d1e",
"account": "53bf504ac0716cbc113fbac5",
"day": "2014-07-10T00:00:00.000Z",
"owner": "53bf504ac0716cbc113fbac4",
"transactions": [
{
"amount": -5,
"added": "2014-07-10T02:47:38.182Z"
}
],
"balance": -5
},
{
"_id": "53bf504a79b21601f0c00d1f",
"account": "53bf504ac0716cbc113fbac5",
"day": "2014-07-02T00:00:00.000Z",
"owner": "53bf504ac0716cbc113fbac4",
"transactions": [
{
"amount": 10,
"added": "2014-07-02T00:00:00.000Z"
}
],
"balance": 10
}
]
Merged Pretty
========================================================================
{
"_id": "53bf504ac0716cbc113fbac5",
"owner": {
"_id": "53bf504ac0716cbc113fbac4",
"name": "bill",
"__v": 0,
"accounts": [
"53bf504ac0716cbc113fbac5"
]
},
"__v": 0,
"balance": 25,
"transactions": [
{
"amount": -5,
"added": "2014-07-11T03:47:38.170Z"
},
{
"amount": 10,
"added": "2014-07-11T02:47:38.153Z"
},
{
"amount": 15,
"added": "2014-07-11T01:47:38.176Z"
},
{
"amount": -5,
"added": "2014-07-10T02:47:38.182Z"
},
{
"amount": 10,
"added": "2014-07-02T00:00:00.000Z"
}
]
}
따라 갔다. 배열에 지속적으로 추가하거나 많은 양의 트랜잭션을 추가하는 지혜에 대한 아이디어가있었습니다. –