发布所有文档,但通过userId过滤文档数组中的值

时间:2017-07-30 20:34:20

标签: meteor

我有以下文档结构:

ProductDocument {
    _id: "a",
    price: 12,
    starredByUserIds: [
       "user1id",
       "user2id",
       "user3id",
    ]
}

为了安全起见,我想通过客户端控制台执行查询,确保给定用户无法看到其他用户的starredByUserIds。

即。 user3应该只能看到自己的条目:

ProductDocument {
    _id: "a",
    price: 12,
    starredByUserIds: [
       "user3id",
    ]
}

虽然未登录的用户应该只能看到:

ProductDocument {
    _id: "a",
    price: 12,
    starredByUserIds: [
    ]
}

我似乎无法定义正确的Publish命令。我喜欢能够做类似的事情:

Meteor.publish('Products', function() {
    return Products.find( {}, { fields: { starredByUserIds: this.userId }} );
})

但是'fields'不接受/匹配任意字符串值。

如何实现这一目标?

3 个答案:

答案 0 :(得分:2)

我认为以下查询应该符合您的要求:

Products.find({}, {starredByUserIds: {$elemMatch:{$eq:this.userId}});

答案 1 :(得分:1)

以下代码段可行:

Meteor.publish('Products', function() {
    return Products.find( {starredByUserIds: this.UserId}, { fields: { starredByUserIds: 0 }} );
})

<强>解释: 此处查询选择器starredByUserIds: this.UserId将仅返回其starredByUserIds数组中具有当前用户ID的文档。

我在将starredByUserIds数组发送到客户端时省略它,因为如果用户已登录,它将包含当前用户的ID,如果用户未登录则将为空in,你可以重新生成它。

答案 2 :(得分:1)

考虑到这些安全问题,您可能应该更改数据模型并将“星标”放在不同的集合中。如果您不想这样做,那么您必须将发布函数的代码更改为以下内容:

Meteor.publish('Products', function () {
  return Products.find().fetch().map(function (product) {
    if (this.userId && product.starredByUserIds.indexOf(this.userId) != -1) {
      product.starredByUserIds = [this.userId];
    } else {
      product.starredByUserIds = [];
    }
    return product;
  });
});