- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在运行聚合管道然后填充后,我试图获得特定的数据模型,但我只是达不到它。
最终想要的结果如下:
[
{
_accountId: "5beee0966d17bc42501f1234",
name: "Company Name 1",
contactEmail: "email1@email.com",
contactName: "contact Name 1"
reason: "Warranties",
total: 1152,
lineItems: [
{
_id: "5beee0966d17bc42501f5086",
jobsiteAddress: "1234 Street Southwest Sunnyville, Wyoming 12345",
warrantyFee: 384
},
{
_id: "5bf43929e7179a56e21382bc",
jobsiteAddress: "1234 Street Southwest Sunnyville, Wyoming 12345",
warrantyFee: 384
},
{
_id: "5bf4392fe7179a56e21382bd",
jobsiteAddress: "1234 Street Southwest Sunnyville, Wyoming 12345",
warrantyFee: 384
}
]
},
{
_accountId: "5beee0966d17bc42501f1235",
name: "Company Name 2",
contactEmail: "email2@email.com",
contactName: "contact Name 2"
reason: "Warranties",
total: 1152,
lineItems: [
{
_id: "5beee0966d17bc42501f5086",
jobsiteAddress: "1234 Street Southwest Sunnyville, Wyoming 12345",
warrantyFee: 384
},
{
_id: "5bf43929e7179a56e21382bc",
jobsiteAddress: "1234 Street Southwest Sunnyville, Wyoming 12345",
warrantyFee: 384
},
{
_id: "5bf4392fe7179a56e21382bd",
jobsiteAddress: "1234 Street Southwest Sunnyville, Wyoming 12345",
warrantyFee: 384
}
]
}
]
{
_id: "5beee0966d17bc42501f5086",
jobsiteAddressStreet: String,
jobsiteAddressCity: String,
jobsiteAddressState" String,
jobsiteAddressZip: Number,
warrantyFee: Number,
_accountId: {
type: Schema.Types.ObjectId,
ref: "accounts"
},
payStatus: String
}
{
_id: "5beee0966d17bc42501f1235",
name: String,
contactName: String,
contactEmail: String
}
Warranty.aggregate([
{
$match: {
payStatus: "Invoiced Next Billing Cycle"
}
},
{
$group: {
_id: "$_accountId",
total: {
$sum: "$warrantyFee"
},
lineItems: {
$push: {
_id: "$_id",
jobsiteAddress: {
$concat: [
"$jobsiteAddressStreet",
" ",
"$jobsiteAddressCity",
", ",
"$jobsiteAddressState",
" ",
"$jobsiteAddressZip"
]
},
warrantyFee: "$warrantyFee"
}
}
}
},
{
$project: {
reason: "Warranties",
total: "$total",
lineItems: "$lineItems"
}
}
])
.then(warranties => {
console.log(warranties);
Account.populate(warranties, {
path: "_id",
select: "contactName contactEmail name"
})
.then(warranties => {
res.send(warranties);
})
.catch(err => {
res.status(422).send(err);
throw err;
});
})
.catch(err => {
res.status(422).send(err);
throw err;
});
[
{
_id: {
_id: "5bc39dfa331c0e2cb897b61e",
name: "Company Name 1",
contactEmail: "email1@email.com",
contactName: "Contact Name 1"
},
reason: "Warranties",
total: 1152,
lineItems: [
{
_id: "5beee0966d17bc42501f5086",
jobsiteAddress: "1234 Street Southwest Sunnyville, Wyoming 12345",
warrantyFee: 384
},
{
_id: "5bf43929e7179a56e21382bc",
jobsiteAddress: "1234 Street Southwest Sunnyville, Wyoming 12345",
warrantyFee: 384
},
{
_id: "5bf4392fe7179a56e21382bd",
jobsiteAddress: "1234 Street Southwest Sunnyville, Wyoming 12345",
warrantyFee: 384
}
]
},
{
_id: {
_id: "5bc39dfa331c0e2cb897b61e",
name: "Company Name 2",
contactEmail: "email2@email.com",
contactName: "Contact Name 2"
},
reason: "Warranties",
total: 1152,
lineItems: [
{
_id: "5beee0966d17bc42501f5086",
jobsiteAddress: "1234 Street Southwest Sunnyville, Wyoming 12345",
warrantyFee: 384
},
{
_id: "5bf43929e7179a56e21382bc",
jobsiteAddress: "1234 Street Southwest Sunnyville, Wyoming 12345",
warrantyFee: 384
},
{
_id: "5bf4392fe7179a56e21382bd",
jobsiteAddress: "1234 Street Southwest Sunnyville, Wyoming 12345",
warrantyFee: 384
}
]
}
]
Warranty.aggregate([
{
$match: {
payStatus: "Invoiced Next Billing Cycle"
}
},
{
$group: {
_id: "$_accountId",
total: {
$sum: "$warrantyFee"
},
lineItems: {
$push: {
_id: "$_id",
jobsiteAddress: {
$concat: [
"$jobsiteAddressStreet",
" ",
"$jobsiteAddressCity",
", ",
"$jobsiteAddressState",
" ",
"$jobsiteAddressZip"
]
},
warrantyFee: "$warrantyFee"
}
}
}
},
{
$lookup: {
from: Account.collection.name,
localField: "_id",
foreignField: "_id",
as: "accounts"
}
},
{
$unwind: "$accounts"
},
{
$project: {
lineItems: "$lineItems",
reason: "Warranties",
total: "$total",
type: "Invoice",
date: new Date(),
company: "$accounts.name",
contactName: "$accounts.contactName",
contactEmail: "$accounts.contactEmail"
}
},
{
$addFields: {
_accountId: "$_id"
}
},
{
$project: {
_id: 0
}
}
])
[
{
lineItems: [
{
_id: "5be203eb3afd8098d4988152",
jobsiteAddress: "1234 Street Southwest Sunnyville, Wyoming 12345",
warrantyFee: 384
}
],
reason: "Warranties",
total: 384,
type: "Invoice",
date: "2018-11-21T14:08:15.052Z",
company: "Company Name 1",
contactName: "Contact Name 1",
contactEmail: "email1@email.com",
_accountId: "5be203eb3afd8098d4988152",
referenceNumber: 1542809296615
},
{
lineItems: [
{
_id: "5beee0966d17bc42501f5086",
jobsiteAddress: "1234 Street Southwest Sunnyville, Wyoming 12345",
warrantyFee: 384
},
{
_id: "5bf43929e7179a56e21382bc",
jobsiteAddress: "1234 Street Southwest Sunnyville, Wyoming 12345",
warrantyFee: 384
},
{
_id: "5bf4392fe7179a56e21382bd",
jobsiteAddress: "1234 Street Southwest Sunnyville, Wyoming 12345",
warrantyFee: 384
}
],
reason: "Warranties",
total: 1152,
type: "Invoice",
date: "2018-11-21T14:08:15.052Z",
company: "Company Name 2",
contactName: "Contact Name 2",
contactEmail: "email2@email.com",
_accountId: "5bc39dfa331c0e2cb897b61e",
referenceNumber: 1542809295680
}
]
最佳答案
因此,当您要求“填充”聚合结果时,您实际上在这里遗漏了一些概念。通常这不是您实际执行的操作,而是解释要点:
aggregate()
的输出不像 Model.find()
或类似的行动,因为这里的目的是“重塑结果”。这基本上意味着您用作聚合源的模型不再被视为输出模型。如果您在输出时仍然保持完全相同的文档结构,这甚至是正确的,但在您的情况下,输出显然与源文档不同。Warranty
的实例您正在采购的模型,但只是一个普通对象。我们可以在稍后讨论时解决这个问题。 populate()
反正有点“老帽子”。这实际上只是在实现初期添加到 Mongoose 的便利功能。它真正做的只是对单独集合中的相关数据执行“另一个查询”,然后将内存中的结果合并到原始集合输出中。$lookup
聚合管道阶段,MongoDB 使用该阶段从另一个集合返回匹配项。不像 populate()
这实际上是在对服务器的单个请求中通过单个响应完成的。这避免了网络开销,通常更快,并且作为“真正的加入”允许您做populate()
的事情。无法做到。 populate()
在
.then()
返回结果后,您要做的是添加
$lookup
到管道:
{ "$lookup": {
"from": Account.collection.name,
"localField": "_id",
"foreignField": "_id",
"as": "accounts"
}},
{ "$unwind": "$accounts" },
{ "$project": {
"_id": "$accounts",
"total": 1,
"lineItems": 1
}}
$lookup
的输出是
总是 数组。是否只有一项相关项或许多项要作为输出获取并不重要。管道阶段将查找
"localField"
的值来自当前文档并使用它来匹配
"foreignField"
中的值指定的。在这种情况下,它是
_id
来自聚合
$group
目标为
_id
国外收藏。
$unwind
紧接在
$lookup
之后的舞台.所有这些都会为目标数组中返回的每个项目返回一个新文档,在这种情况下,您希望它是一个。在
_id
的情况下在外部集合中不匹配,没有匹配的结果将被删除。
$unwind
指令实际上合并到
$lookup
以高效的方式运作。你可以在那里阅读更多相关信息。
populate()
这是错误的做法。除了输出不再由
Warranty
组成的基本事实之外模型对象,该模型实际上只知道
_accountId
中描述的外部项目无论如何都不存在于输出中的属性。
// Special models
const outputSchema = new Schema({
_id: { type: Schema.Types.ObjectId, ref: "Account" },
total: Number,
lineItems: [{ address: String }]
});
const Output = mongoose.model('Output', outputSchema, 'dontuseme');
Output
然后可以使用模型将生成的纯 JavaScript 对象“转换”到 Mongoose 文档中,以便像
Model.populate()
这样的方法。实际上可以称为:
// excerpt
result2 = result2.map(r => new Output(r)); // Cast to Output Mongoose Documents
// Call populate on the list of documents
result2 = await Output.populate(result2, { path: '_id' })
log(result2);
Output
定义了一个架构,它知道
_id
上的“引用”它的文档领域
Model.populate()
知道它需要做什么并返回项目。
Mongoose: warranties.aggregate([ { '$match': { payStatus: 'Invoiced Next Billing Cycle' } }, { '$group': { _id: '$_accountId', total: { '$sum': '$warrantyFee' }, lineItems: { '$push': { _id: '$_id', address: { '$trim': { input: { '$reduce': { input: { '$objectToArray': '$address' }, initialValue: '', in: { '$concat': [ '$$value', ' ', [Object] ] } } }, chars: ' ' } } } } } } ], {})
Mongoose: accounts.find({ _id: { '$in': [ ObjectId("5bf4b591a06509544b8cf75c"), ObjectId("5bf4b591a06509544b8cf75b") ] } }, { projection: {} })
Account
模型条目。
$lookup
并获得真正的“加入”,这不是
populate()
实际上是在做。
const { Schema } = mongoose = require('mongoose');
const uri = 'mongodb://localhost:27017/joindemo';
const opts = { useNewUrlParser: true };
// Sensible defaults
mongoose.Promise = global.Promise;
mongoose.set('debug', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndex', true);
// Schema defs
const warrantySchema = new Schema({
address: {
street: String,
city: String,
state: String,
zip: Number
},
warrantyFee: Number,
_accountId: { type: Schema.Types.ObjectId, ref: "Account" },
payStatus: String
});
const accountSchema = new Schema({
name: String,
contactName: String,
contactEmail: String
});
// Special models
const outputSchema = new Schema({
_id: { type: Schema.Types.ObjectId, ref: "Account" },
total: Number,
lineItems: [{ address: String }]
});
const Output = mongoose.model('Output', outputSchema, 'dontuseme');
const Warranty = mongoose.model('Warranty', warrantySchema);
const Account = mongoose.model('Account', accountSchema);
// log helper
const log = data => console.log(JSON.stringify(data, undefined, 2));
// main
(async function() {
try {
const conn = await mongoose.connect(uri, opts);
// clean models
await Promise.all(
Object.entries(conn.models).map(([k,m]) => m.deleteMany())
)
// set up data
let [first, second, third] = await Account.insertMany(
[
['First Account', 'First Person', 'first@example.com'],
['Second Account', 'Second Person', 'second@example.com'],
['Third Account', 'Third Person', 'third@example.com']
].map(([name, contactName, contactEmail]) =>
({ name, contactName, contactEmail })
)
);
await Warranty.insertMany(
[
{
address: {
street: '1 Some street',
city: 'Somewhere',
state: 'TX',
zip: 1234
},
warrantyFee: 100,
_accountId: first,
payStatus: 'Invoiced Next Billing Cycle'
},
{
address: {
street: '2 Other street',
city: 'Elsewhere',
state: 'CA',
zip: 5678
},
warrantyFee: 100,
_accountId: first,
payStatus: 'Invoiced Next Billing Cycle'
},
{
address: {
street: '3 Other street',
city: 'Elsewhere',
state: 'NY',
zip: 1928
},
warrantyFee: 100,
_accountId: first,
payStatus: 'Invoiced Already'
},
{
address: {
street: '21 Jump street',
city: 'Anywhere',
state: 'NY',
zip: 5432
},
warrantyFee: 100,
_accountId: second,
payStatus: 'Invoiced Next Billing Cycle'
}
]
);
// Aggregate $lookup
let result1 = await Warranty.aggregate([
{ "$match": {
"payStatus": "Invoiced Next Billing Cycle"
}},
{ "$group": {
"_id": "$_accountId",
"total": { "$sum": "$warrantyFee" },
"lineItems": {
"$push": {
"_id": "$_id",
"address": {
"$trim": {
"input": {
"$reduce": {
"input": { "$objectToArray": "$address" },
"initialValue": "",
"in": {
"$concat": [ "$$value", " ", { "$toString": "$$this.v" } ] }
}
},
"chars": " "
}
}
}
}
}},
{ "$lookup": {
"from": Account.collection.name,
"localField": "_id",
"foreignField": "_id",
"as": "accounts"
}},
{ "$unwind": "$accounts" },
{ "$project": {
"_id": "$accounts",
"total": 1,
"lineItems": 1
}}
])
log(result1);
// Convert and populate
let result2 = await Warranty.aggregate([
{ "$match": {
"payStatus": "Invoiced Next Billing Cycle"
}},
{ "$group": {
"_id": "$_accountId",
"total": { "$sum": "$warrantyFee" },
"lineItems": {
"$push": {
"_id": "$_id",
"address": {
"$trim": {
"input": {
"$reduce": {
"input": { "$objectToArray": "$address" },
"initialValue": "",
"in": {
"$concat": [ "$$value", " ", { "$toString": "$$this.v" } ] }
}
},
"chars": " "
}
}
}
}
}}
]);
result2 = result2.map(r => new Output(r));
result2 = await Output.populate(result2, { path: '_id' })
log(result2);
} catch(e) {
console.error(e)
} finally {
process.exit()
}
})()
Mongoose: dontuseme.deleteMany({}, {})
Mongoose: warranties.deleteMany({}, {})
Mongoose: accounts.deleteMany({}, {})
Mongoose: accounts.insertMany([ { _id: 5bf4b591a06509544b8cf75b, name: 'First Account', contactName: 'First Person', contactEmail: 'first@example.com', __v: 0 }, { _id: 5bf4b591a06509544b8cf75c, name: 'Second Account', contactName: 'Second Person', contactEmail: 'second@example.com', __v: 0 }, { _id: 5bf4b591a06509544b8cf75d, name: 'Third Account', contactName: 'Third Person', contactEmail: 'third@example.com', __v: 0 } ], {})
Mongoose: warranties.insertMany([ { _id: 5bf4b591a06509544b8cf75e, address: { street: '1 Some street', city: 'Somewhere', state: 'TX', zip: 1234 }, warrantyFee: 100, _accountId: 5bf4b591a06509544b8cf75b, payStatus: 'Invoiced Next Billing Cycle', __v: 0 }, { _id: 5bf4b591a06509544b8cf75f, address: { street: '2 Other street', city: 'Elsewhere', state: 'CA', zip: 5678 }, warrantyFee: 100, _accountId: 5bf4b591a06509544b8cf75b, payStatus: 'Invoiced Next Billing Cycle', __v: 0 }, { _id: 5bf4b591a06509544b8cf760, address: { street: '3 Other street', city: 'Elsewhere', state: 'NY', zip: 1928 }, warrantyFee: 100, _accountId: 5bf4b591a06509544b8cf75b, payStatus: 'Invoiced Already', __v: 0 }, { _id: 5bf4b591a06509544b8cf761, address: { street: '21 Jump street', city: 'Anywhere', state: 'NY', zip: 5432 }, warrantyFee: 100, _accountId: 5bf4b591a06509544b8cf75c, payStatus: 'Invoiced Next Billing Cycle', __v: 0 } ], {})
Mongoose: warranties.aggregate([ { '$match': { payStatus: 'Invoiced Next Billing Cycle' } }, { '$group': { _id: '$_accountId', total: { '$sum': '$warrantyFee' }, lineItems: { '$push': { _id: '$_id', address: { '$trim': { input: { '$reduce': { input: { '$objectToArray': '$address' }, initialValue: '', in: { '$concat': [ '$$value', ' ', [Object] ] } } }, chars: ' ' } } } } } }, { '$lookup': { from: 'accounts', localField: '_id', foreignField: '_id', as: 'accounts' } }, { '$unwind': '$accounts' }, { '$project': { _id: '$accounts', total: 1, lineItems: 1 } } ], {})
[
{
"total": 100,
"lineItems": [
{
"_id": "5bf4b591a06509544b8cf761",
"address": "21 Jump street Anywhere NY 5432"
}
],
"_id": {
"_id": "5bf4b591a06509544b8cf75c",
"name": "Second Account",
"contactName": "Second Person",
"contactEmail": "second@example.com",
"__v": 0
}
},
{
"total": 200,
"lineItems": [
{
"_id": "5bf4b591a06509544b8cf75e",
"address": "1 Some street Somewhere TX 1234"
},
{
"_id": "5bf4b591a06509544b8cf75f",
"address": "2 Other street Elsewhere CA 5678"
}
],
"_id": {
"_id": "5bf4b591a06509544b8cf75b",
"name": "First Account",
"contactName": "First Person",
"contactEmail": "first@example.com",
"__v": 0
}
}
]
Mongoose: warranties.aggregate([ { '$match': { payStatus: 'Invoiced Next Billing Cycle' } }, { '$group': { _id: '$_accountId', total: { '$sum': '$warrantyFee' }, lineItems: { '$push': { _id: '$_id', address: { '$trim': { input: { '$reduce': { input: { '$objectToArray': '$address' }, initialValue: '', in: { '$concat': [ '$$value', ' ', [Object] ] } } }, chars: ' ' } } } } } } ], {})
Mongoose: accounts.find({ _id: { '$in': [ ObjectId("5bf4b591a06509544b8cf75c"), ObjectId("5bf4b591a06509544b8cf75b") ] } }, { projection: {} })
[
{
"_id": {
"_id": "5bf4b591a06509544b8cf75c",
"name": "Second Account",
"contactName": "Second Person",
"contactEmail": "second@example.com",
"__v": 0
},
"total": 100,
"lineItems": [
{
"_id": "5bf4b591a06509544b8cf761",
"address": "21 Jump street Anywhere NY 5432"
}
]
},
{
"_id": {
"_id": "5bf4b591a06509544b8cf75b",
"name": "First Account",
"contactName": "First Person",
"contactEmail": "first@example.com",
"__v": 0
},
"total": 200,
"lineItems": [
{
"_id": "5bf4b591a06509544b8cf75e",
"address": "1 Some street Somewhere TX 1234"
},
{
"_id": "5bf4b591a06509544b8cf75f",
"address": "2 Other street Elsewhere CA 5678"
}
]
}
]
关于mongodb - 聚合后 Mongoose 填充,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53399775/
当我保存4条记录时,我需要将它们一一保存,所以我的代码是 a.save(function(){ b.save(function(){ c.save(function(){ d.save(f
Mongoose在版本4.2.7中创建了一个新的单个子文档功能(documentation和feature request),允许使用单个嵌入式子文档架构,其行为方式与一对多子文档的行为相同。 在父级
Mongoose 版本 >= 4.0 有一个时间戳选项,当 timestamps 设置为 时,该选项会为架构创建 updatedAt 和 createdAt 字段正确。 http://mongoose
我注意到某些图书馆喜欢 mock 鹅 ( https://github.com/mccormicka/Mockgoose/blob/master/test/index.spec.js ) 使用 req
我正在与 Mongoose 合作。我见过很多开发者发出以下命令: mongoose.Promise = global.Promise; 然后我很好奇 mongoose.Promise 的原始值是什么。
当我运行与数据库大量连接和断开连接的测试时,我收到以下警告。 (node) warning: possible EventEmitter memory leak detected. 11 connec
我可以在 Mongoose 的子文档数组中填充动态引用(使用“refPath”)虚拟字段吗? 数据结构如下 Group - Members -> User 代码:模型/模式 let MemberSc
我正在我的应用程序中做一些测试,看看内存缓存是否真的在工作。但是,由于 memory-cache 显然没有公开“命中”事件,我无法判断是否真的从缓存中获取数据。所以我试着看看当应用程序实际从数据库中获
我是 nestjs 的新手。我使用 @nestjs/mongoose,我需要在我的类模式中引用嵌套对象中的几个字段,但我不知道该怎么做。 dietDays 对象必须包含一个日期字段和包含对 Meal
我是 mongodb 的新手,我有一个这样的数据模型 { last_updated: Date.now(), csgo_items:[ {name: 'name', p
这是我的方案: var documentSchema = mongoose.Schema({ 'facts': [{ 'type': { type: String, requi
我想删除多个 _ids = ['123', '234', '345']; _ids.forEach(_id => { await model.deleteOne({ _id }); }); 有没有
我有一个像这样的 Mongoose 模式: var Address = { doorNo:String, city:String, state:String, coun
我的文档包含一个名为 clients 的字段那应该包含一组客户端ID。 { "first_name":"Nick", "last_name":"Parsons", "email":"nic
我遇到了以下我无法理解的代码行,尽管有很多教程提供了与 populate 的示例相关的信息。但没有一个能解释它究竟意味着什么。这是一个例子 var mongoose = require('mongoo
我有一个具有多个唯一性的架构,如下所示: var userSchema = new mongoose.Schema({ user: { type: String, unique:
我有一个 Mongoose 模式,其中有 4 个子模式。我一直在关注这里的文档https://github.com/LearnBoost/mongoose关于嵌入文档 var scenarios =
我希望每个字符串属性都默认设置为 true。有办法吗? ?? mongoose.Schema.String -> default { trim: true } var schema = new Sch
我有这个代码 var ClientSchema = new Schema({ name: {type: String, required: true, trim: true} }); var Cl
许多教程告诉您在您的 userSchema 页面中使用 bycrypt。保存新用户后,它会附带加密密码。伟大的。然而,我想,当我用某些东西编辑用户时,它也会重新哈希密码,导致无法登录。你能给我一个解决
我是一名优秀的程序员,十分优秀!