Mongodb Mongoose模式:使数组中的对象具有文档的唯一字段
我不是在尝试创建一个唯一的数组元素,而是要确保如果我有一个Mongodb Mongoose模式:使数组中的对象具有文档的唯一字段,mongodb,express,mongoose,mongodb-query,mongoose-schema,Mongodb,Express,Mongoose,Mongodb Query,Mongoose Schema,我不是在尝试创建一个唯一的数组元素,而是要确保如果我有一个对的数组(它们是对象),那么所有对都有不同的值 以下是我的模式的定义: const redirectSchema = new mongoose.Schema({ username: { type: String, required: true, }, name: { type: String, required: true, uniqu
对的数组(它们是对象),那么所有对都有不同的值
以下是我的模式的定义:
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
}
})
例如,像这样插入一对就可以了
{
code: "US",
site: "google.com"
}
但是,在本文档中插入另一个具有相同代码的对
,无论是站点
,都是不合适的
{
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):
我的代码中的问题在于,我使用了forEach
查找来遍历文档数组中的对对象。
由于我在我的POST
路径中使用了async
函数,因此我进行了一些搜索,发现forEach
函数在async
函数中不能很好地发挥作用。
这是我的密码
获取文档并检查对
数组
如果pairs
包含具有请求代码的对象,则返回错误消息
如果不是,则将对
对象添加到文档中
//将对添加到给定重定向
router.post('/:name/insert_pair',verifyToken,异步(请求,响应)=>{
const token=request.header(“身份验证令牌”)
const usernameFromToken=jwt.decode(token).username
const{code,site}=request.body
//请记住:您只能编辑自己的内容
试一试{
//将对象作为纯JSON获取,并检查它是否包含代码
const check=wait Redirect.findOne(
{
用户名:usernameFromToken,
名称:request.params.name
}
).lean()
//解决方案:不要在异步中使用FOREACH!
for(设i=0;i{
//如果(pair.code==代码){
//返回response.status(400.json)({
//消息:`${request.params.name}已包含${code}的条目`
// })
// }
// })
//编辑
等待重定向。findOneAndUpdate(
{
用户名:usernameFromToken,
名称:request.params.name
},
{
$push:{
成对:{code,site}
}
}
)
//让它显示在屏幕上
const display=await Redirect.findOne(
{
用户名:usernameFromToken,
名称:request.params.name
})
json(显示)
}捕获(错误){
response.status(400.json)(错误)
}
})
// 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)
}
// 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)
}
})