哪个更糟?还有一个db访问或一个过时的值?

时间:2015-09-04 02:03:01

标签: javascript angularjs node.js mongodb mongoose

问题

我正在使用AngularJS,Node JS,Express和MongoDB运行应用程序。我正在接受MongoDB进入猫鼬。我的问题是我有一张剑,每个人都是伪造的。但是,要访问某人的个人资料,我需要使用某人的ID。该ID是唯一的。但我不能将链接显示为链接'352384b685326vyad6'。因此,当有人创造一把剑时,我会将他或她的名字存储在剑信息中。

例如,要显示剑的列表,我可以这样做:

<div ng-repeat='sword in swords'>
  <p> Sword name: {{sword.name}} </p>
  <p> Author: <a href='#/user/{{sword.createdByID}}'> {{sword.createdByName}} </a> </p>
</div>

但是,如果用户更改了他的名字,剑将不会相应地更新他的创建者名称。我该怎么办?我已经想到了一些解决方案,但我不知道哪种解决方案可以解决这个问题。

  • 当有人更改自己的名字时,我可以使用新的用户名和ID发出POST请求,更新已创建的所有剑等于用户ID。但我觉得这太奇怪了。

    SwordModel.find({ createdByID: req.body.id}, [...]);
    
  • 当通过GET请求在控制器中加载剑时,为每把剑发出另一个GET请求,并根据sword.createdById更新sword.username。

    UserModel.findById(req.body.id), [...]);
    
  • 忘记用户体验并使用丑陋的链接。

我想知道如何在不影响我的数据库的情况下更新每把剑的用户名感谢您的任何建议。

MODELS - 仅供参考。

sword.js

var mongoose = require('mongoose');
var SwordModel = mongoose.model('SwordModel', 
    {
        name: String,           //Sword's name
        createdById: String,    //ID of the user who created.
        createdByName: String   //Name of the user
    });
module.exports = mongoose.model('SwordModel', SwordModel);

user.js的

var mongoose = require('mongoose');
var UserModel = mongoose.model('UserModel', 
    {
        name: String,           //Name of the user.
        ID: String              //ID of the user.
    });
module.exports = mongoose.model('UserModel', UserModel);

2 个答案:

答案 0 :(得分:3)

如果您使用Mongoose架构,则可以通过引用Swords中的User来执行此操作。 在引用另一个模式后,您可以使用populate方法获得所需的结果。

示例(可能不完全相同,但类似于以下内容):

Sword Schema:

var swordSchema = new Schema({
    name: String,
    createdBy: {type: mongoose.Schema.Types.ObjectId, ref: 'User'}
});

使用架构制作模型:

var swordModel =  mongoose.model('Sword', swordSchema);

使用populate查找您要查找的内容。

请参阅此处填写的完整文档 - http://mongoosejs.com/docs/populate.html

编辑:请注意,我建议仅在用户模型中保留用户名,并仅引用它。

答案 1 :(得分:1)

我认为我们的技术问题较少,而且概念问题更多。

约束

我理所当然地认为......

  • 用户可以更改其用户名
  • 用户名是唯一的
  • 您只需提供指向用户的链接,按名称
  • 显示

此外,我将使用普通的JSON和MongoDB,并相信您可以将其转换为Mongoose。

解决方案

虽然用户可以更改用户名,但这种情况不会经常发生。更常见的用例是您需要链接到用户名。因此,我们首先需要了解如何有效地处理该用例。

因为你只需要给定剑的史密斯的名字,所以剑模型没有错误,如

{
  _id: new ObjectId(),
  name: "Libertas",
  smith: "Foobar"
}

要在用户集合中有效地找到“Foobar”,我们只需在此处添加索引(如果尚未完成):

db.users.createIndex({username:1}, {unique:true})

您的服务可以使用

进行有效查询
db.users.find({name: "Foobar"})

无需在剑文档中保存用户的_id,但您仍然可以有效地查询它。

处理用户名的更改是一个很少执行的用例,所以在这里优化是没有意义的。但是,如果用户更改了用户名,您的服务可以通过

轻松实现
db.swords.update(
  { smith:"Foobar" },
  { $set:{ smith: "CoolNewUsername" },
  { multi: true, writeConcern: { w:1, j:true }
)

上面的最后一行需要一点解释。 multi: true选项告诉MongoDB更改匹配{smith: "Foobar"}的所有文档,而不仅仅是找到的第一个,这很容易理解。但为什么要将写入问题设置为journaled?第一个原因是无论为连接配置的写入问题(甚至可能是unacknowledged),我们都需要这些更改是持久的。但是,我们通常不需要将更改传播到更多副本集成员,因此选择的写入关注点可以为您提供最佳性能,同时您仍然可以确保更改已同步到磁盘。如果您需要更高的耐用性,当然可以将写入问题设置为{w:2} or {w:"majority"}

优点

  1. 对于这种关系的最常见用例(显示伪造给定剑的用户的链接),执行此操作所需的所有信息都包含在剑的文档中,以防止可能不必要的查询。
  2. 但是,如果用户点击了所述链接,则可以有效地查询给定剑的史密斯。
  3. 可以更改用户名,并且可以非常有效和持久地实现
  4. 缺点

    这里的主要缺点是,当用户更改用户名时,你实际上来修改所有受影响的剑,而使用Mongoose引用是不必要的。但是,由于这是一种罕见的用例,并且使用populate会导致整个用户文档被加载到只需要用户名的地方,我认为这个缺点可以忽略不计。基本上,您正在进行交易,以便将普通用例所需的查询减少一半,而不需要手动更新,而这种情况很少发生。

    我没有看到任何其他缺点。