猫鼬模式:使数组中的对象具有文档的唯一字段
Mongoose Schema: making an object within an array have a unique field for the document
我 不是 试图制作一个独特的数组元素,而是确保如果我有一个 pairs
的数组(它们是对象)都有不同的code
的值。
这是我的架构定义:
const redirectSchema = new mongoose.Schema({
username: {
type: String,
required: true,
},
name: {
type: String,
required: true,
unique: true
},
default_link: {
type: String,
required: true,
},
pairs: [
{
code: { // I want this field specifically to be unique within the document only
type: String,
required: true
},
site: {
type: String,
required: true
}
}
],
date: {
type: Date,
required: true,
default: Date.now
}
})
因此,例如,像这样插入一个 pair
就可以了。
{
code: "US",
site: "google.com"
}
但是在本文档中插入另一个具有相同 code
的 pair
应该是不行的,无论 site
.
{
code: "US", // Should not work, since the code "US" already exists within the array of pairs
site: "amazon.com"
}
我正在尝试使用 Redirect.findOne()
和 Redirect.updateOne()
来执行此操作,但我一直遇到编译器错误,或者只有在重复项已经存在后才会执行检查。
这是我目前的路线(允许重复 code
s):
// Add pair to given redirect
router.post('/:name/insert_pair', verifyToken, async (request, response) => {
const token = request.header("auth-token")
const usernameFromToken = jwt.decode(token).username
const { code, site } = request.body
// Remember: you may edit only your own content
try {
const edited = await Redirect.findOneAndUpdate(
{
username: usernameFromToken,
name: request.params.name
},
{
$push: {
pairs: { code, site }
}
}
)
const specific = await Redirect.findOne(
{
username: usernameFromToken,
name: request.params.name
})
response.send(specific)
} catch (error) {
response.status(400).json(error)
}
我的代码中的问题在于我使用 forEach
外观来遍历文档数组中的 pair
对象。
由于我为 POST
路线使用了 async
函数,我进行了一些搜索,发现 forEach
在 async
函数。 我改用旧式 for (let i = 0;
循环,现在可以正常工作了!
这是我的代码。
获取文档并检查pairs
数组
如果 pairs
包含具有请求代码的对象,return 一条错误消息。
如果没有,请将 pair
对象添加到文档中。
// Add pair to given redirect
router.post('/:name/insert_pair', verifyToken, async (request, response) => {
const token = request.header("auth-token")
const usernameFromToken = jwt.decode(token).username
const { code, site } = request.body
// Remember: you may edit only your own content
try {
// Get the object as plain JSON and check if it contains the code
const check = await Redirect.findOne(
{
username: usernameFromToken,
name: request.params.name
}
).lean()
// SOLUTION: DON'T USE FOREACH WITHIN ASYNC!
for (let i = 0; i < check.pairs.length; i++) {
if (check.pairs[i].code === code) {
return response.status(400).json({
message: `${request.params.name} already contains an entry for ${code}`
})
}
}
// TODO BUG: ONLY WORKS AFTER 1 DUPLICATE HAS ALREADY BEEN MADE.
// await check.pairs.forEach((pair) => {
// if (pair.code === code) {
// return response.status(400).json({
// message: `${request.params.name} already contains an entry for ${code}`
// })
// }
// })
// Make the edit
await Redirect.findOneAndUpdate(
{
username: usernameFromToken,
name: request.params.name
},
{
$push: {
pairs: { code, site }
}
}
)
// Get it to display it on screen
const display = await Redirect.findOne(
{
username: usernameFromToken,
name: request.params.name
})
response.json(display)
} catch (error) {
response.status(400).json(error)
}
})
我 不是 试图制作一个独特的数组元素,而是确保如果我有一个 pairs
的数组(它们是对象)都有不同的code
的值。
这是我的架构定义:
const redirectSchema = new mongoose.Schema({
username: {
type: String,
required: true,
},
name: {
type: String,
required: true,
unique: true
},
default_link: {
type: String,
required: true,
},
pairs: [
{
code: { // I want this field specifically to be unique within the document only
type: String,
required: true
},
site: {
type: String,
required: true
}
}
],
date: {
type: Date,
required: true,
default: Date.now
}
})
因此,例如,像这样插入一个 pair
就可以了。
{
code: "US",
site: "google.com"
}
但是在本文档中插入另一个具有相同 code
的 pair
应该是不行的,无论 site
.
{
code: "US", // Should not work, since the code "US" already exists within the array of pairs
site: "amazon.com"
}
我正在尝试使用 Redirect.findOne()
和 Redirect.updateOne()
来执行此操作,但我一直遇到编译器错误,或者只有在重复项已经存在后才会执行检查。
这是我目前的路线(允许重复 code
s):
// Add pair to given redirect
router.post('/:name/insert_pair', verifyToken, async (request, response) => {
const token = request.header("auth-token")
const usernameFromToken = jwt.decode(token).username
const { code, site } = request.body
// Remember: you may edit only your own content
try {
const edited = await Redirect.findOneAndUpdate(
{
username: usernameFromToken,
name: request.params.name
},
{
$push: {
pairs: { code, site }
}
}
)
const specific = await Redirect.findOne(
{
username: usernameFromToken,
name: request.params.name
})
response.send(specific)
} catch (error) {
response.status(400).json(error)
}
我的代码中的问题在于我使用 forEach
外观来遍历文档数组中的 pair
对象。
由于我为 POST
路线使用了 async
函数,我进行了一些搜索,发现 forEach
在 async
函数。 我改用旧式 for (let i = 0;
循环,现在可以正常工作了!
这是我的代码。
获取文档并检查
pairs
数组如果
pairs
包含具有请求代码的对象,return 一条错误消息。如果没有,请将
pair
对象添加到文档中。
// Add pair to given redirect
router.post('/:name/insert_pair', verifyToken, async (request, response) => {
const token = request.header("auth-token")
const usernameFromToken = jwt.decode(token).username
const { code, site } = request.body
// Remember: you may edit only your own content
try {
// Get the object as plain JSON and check if it contains the code
const check = await Redirect.findOne(
{
username: usernameFromToken,
name: request.params.name
}
).lean()
// SOLUTION: DON'T USE FOREACH WITHIN ASYNC!
for (let i = 0; i < check.pairs.length; i++) {
if (check.pairs[i].code === code) {
return response.status(400).json({
message: `${request.params.name} already contains an entry for ${code}`
})
}
}
// TODO BUG: ONLY WORKS AFTER 1 DUPLICATE HAS ALREADY BEEN MADE.
// await check.pairs.forEach((pair) => {
// if (pair.code === code) {
// return response.status(400).json({
// message: `${request.params.name} already contains an entry for ${code}`
// })
// }
// })
// Make the edit
await Redirect.findOneAndUpdate(
{
username: usernameFromToken,
name: request.params.name
},
{
$push: {
pairs: { code, site }
}
}
)
// Get it to display it on screen
const display = await Redirect.findOne(
{
username: usernameFromToken,
name: request.params.name
})
response.json(display)
} catch (error) {
response.status(400).json(error)
}
})