在 Mongoose 中跳过一层嵌套的子文档
Skip one nested level of subdocument in Mongoose
我有一个带有子文档的父架构。子文档有一个 属性 和一个嵌入对象数组:
子架构
var snippetSchema = new Schema({
snippet: [
{
language: String,
text: String,
_id: false
}
]
});
父架构
var itemSchema = new Schema({
lsin: Number,
identifier: {
isbn13: Number,
},
title: snippetSchema,
});
在 Item.find
returns 这样的对象上:
[
{
_id: (...),
lsin: 676765,
identifier: {
isbn13: 8797734598763
},
title: {
_id: (...),
snippet: [
{
language: 'se',
text: 'Pippi Långstrump'
}
]
}
}
]
我想在对象返回给客户端时跳过子文档的一层嵌套:
[
{
_id: (...),
lsin: 676765,
identifier: {
isbn13: 8797734598763
},
title: {
language: 'se',
text: 'Pippi Långstrump'
}
}
]
到目前为止我已经尝试过:
#1 使用 getter
function getter() {
return this.title.snippet[0];
}
var itemSchema = new Schema({
...
title: { type: snippetSchema, get: getter }
});
但它会创建一个无限循环,导致 RangeError: Maximum call stack size exceeded
。
#2 使用虚拟属性
var itemSchema = new Schema({
..., {
toObject: {
virtuals: true
}
});
itemSchema
.virtual('title2')
.get(function () {
return this.title.snippet[0];
});
这将生成所需的嵌套级别但在新属性下,这是不可接受的。据我所知,没有办法用虚拟属性覆盖属性。
问题是:是否有任何其他方法可以获得所需的输出?应用程序中将有多个对 snippetSchema
的引用,首选 DRY 方法。
我是 MongoDB 和 Mongoose 的新手。
您需要在 mongodb 聚合管道中使用 $project
。
在我的数据库中,我有以下内容:
> db.items.find().pretty()
{
"_id" : 123,
"lsin" : 676765,
"identifier" : {
"isbn13" : 8797734598763
},
"title" : {
"_id" : 456,
"snippet" : [
{
"language" : "se",
"text" : "Pippi Långstrump"
}
]
}
}
然后我们只需要创建一个简单的聚合查询:
db.items.aggregate([
{$project: { lsin: 1, identifier: 1, title: { $arrayElemAt: [ '$title.snippet', 0 ] }}}
])
这只是使用 $project (https://docs.mongodb.com/v3.2/reference/operator/aggregation/project/) and a $arrayElemAt (https://docs.mongodb.com/v3.2/reference/operator/aggregation/arrayElemAt/) 将第一项投影到数组之外。如果我们执行它,我们将得到以下内容:
{
"_id" : 123,
"lsin" : 676765,
"identifier" : {
"isbn13" : 8797734598763
},
"title" : {
"language" : "se",
"text" : "Pippi Långstrump"
}
}
我有一个带有子文档的父架构。子文档有一个 属性 和一个嵌入对象数组:
子架构
var snippetSchema = new Schema({
snippet: [
{
language: String,
text: String,
_id: false
}
]
});
父架构
var itemSchema = new Schema({
lsin: Number,
identifier: {
isbn13: Number,
},
title: snippetSchema,
});
在 Item.find
returns 这样的对象上:
[
{
_id: (...),
lsin: 676765,
identifier: {
isbn13: 8797734598763
},
title: {
_id: (...),
snippet: [
{
language: 'se',
text: 'Pippi Långstrump'
}
]
}
}
]
我想在对象返回给客户端时跳过子文档的一层嵌套:
[
{
_id: (...),
lsin: 676765,
identifier: {
isbn13: 8797734598763
},
title: {
language: 'se',
text: 'Pippi Långstrump'
}
}
]
到目前为止我已经尝试过:
#1 使用 getter
function getter() {
return this.title.snippet[0];
}
var itemSchema = new Schema({
...
title: { type: snippetSchema, get: getter }
});
但它会创建一个无限循环,导致 RangeError: Maximum call stack size exceeded
。
#2 使用虚拟属性
var itemSchema = new Schema({
..., {
toObject: {
virtuals: true
}
});
itemSchema
.virtual('title2')
.get(function () {
return this.title.snippet[0];
});
这将生成所需的嵌套级别但在新属性下,这是不可接受的。据我所知,没有办法用虚拟属性覆盖属性。
问题是:是否有任何其他方法可以获得所需的输出?应用程序中将有多个对 snippetSchema
的引用,首选 DRY 方法。
我是 MongoDB 和 Mongoose 的新手。
您需要在 mongodb 聚合管道中使用 $project
。
在我的数据库中,我有以下内容:
> db.items.find().pretty()
{
"_id" : 123,
"lsin" : 676765,
"identifier" : {
"isbn13" : 8797734598763
},
"title" : {
"_id" : 456,
"snippet" : [
{
"language" : "se",
"text" : "Pippi Långstrump"
}
]
}
}
然后我们只需要创建一个简单的聚合查询:
db.items.aggregate([
{$project: { lsin: 1, identifier: 1, title: { $arrayElemAt: [ '$title.snippet', 0 ] }}}
])
这只是使用 $project (https://docs.mongodb.com/v3.2/reference/operator/aggregation/project/) and a $arrayElemAt (https://docs.mongodb.com/v3.2/reference/operator/aggregation/arrayElemAt/) 将第一项投影到数组之外。如果我们执行它,我们将得到以下内容:
{
"_id" : 123,
"lsin" : 676765,
"identifier" : {
"isbn13" : 8797734598763
},
"title" : {
"language" : "se",
"text" : "Pippi Långstrump"
}
}