Mongodb Meteor/Mongo找到一个记录并删除子id的子数组';是基于子字段的吗?

Mongodb Meteor/Mongo找到一个记录并删除子id的子数组';是基于子字段的吗?,mongodb,meteor,mongodb-query,meteor-publications,Mongodb,Meteor,Mongodb Query,Meteor Publications,我在《流星》中有这样的收藏: TagsToArticles = { tag: "Tag1", articles: [ article1Id, article2Id, article3Id ] } 文章集合具有以下架构 Articles = { permission: "private" ... } 这些标签本质上是索引搜索词 每篇文章都有一个权限设置为“私有”、“组”或“公共” 现在,我发布的标签如下: Meteor.publish("allTags", function()

我在《流星》中有这样的收藏:

TagsToArticles = {
  tag: "Tag1",
  articles: [ article1Id, article2Id, article3Id ]
}
文章集合具有以下架构

Articles = {
  permission: "private"
  ...
}
这些标签本质上是索引搜索词

每篇文章都有一个权限设置为“私有”、“组”或“公共”

现在,我发布的标签如下:

Meteor.publish("allTags", function() {
  return TagsToARticles.find({});
}
然后在客户端,我过滤文章列表,只显示那些是公共的或是私有的但由当前用户创建的

然而,理想情况下,出于安全目的,我希望在发布函数本身的服务器端进行过滤,以防止客户端访问私有文章的文章ID。除非客户端具有适当的权限,否则我确实会阻止访问实际的文章对象,但我想更进一步,从结果中完全删除ID

因此,我要寻找的基本上是一个查询,它允许我使用以下伪代码:

TagsToArticles.find({ articles.foreach(articleId) {
  if (Articles.findOne(articleId).permission == 'public') ||
     (Articles.findOne(articleId).ownerId == Meteor.userId())
     include articleId
  }
我最初考虑使用与上面完全相同的函数(基本上获取所有记录,然后遍历每个记录并手动修剪数组,然后返回更新后的记录集)来完成此操作,但我的理解是,如果基础数据发生变化,我将失去Meteor的反应性,记录集也不会更新

如果没有一个find()查询来完成这项工作,那么如果有一种方法可以对一个函数进行额外的传递,并且仍然返回一个反应数据集,那么我也可以使用该解决方案


由于这是一个非规范化的集合(标记也位于articles文档中),我想我还可以进一步非规范化,不仅包括article ID,还包括ownerId和权限。但我仍然不确定如何测试单个数组元素,如果可能的话,我希望尽可能减少需要进行的非规范化量…

在Mongo中甚至不可能进行连接,而且在Mongo数据库中基于连接创建反应式数据集看起来更不现实

但您真的需要反应式数据集吗?您只需订阅文章数据集中的public和userId记录,订阅TagsToArticles中所需的标记,并为枚举文章和标记并返回记录集的模板定义helper。当文章或标记文章中的项目发生更改时,Meteor会自动更新您的HTML

但我仍然不确定如何测试单个数组元素


如果你在文章中有标签,你可以只通过文章集合,从公共和用户文章中收集唯一的标签

你应该考虑使用这个包。

如果我正确理解您的模式,发布代码将如下所示:

Meteor.publishComposite('articles', function() {
  return {
    find: function() {
      return Articles.find({ $or: [ { permission: 'public' }, { ownerId: this.userId } ] });
    },
    children: [{
      find: function(article) {
        return TagsToArticles.find( { articles: article.articleId } );
      }
    }]
  }
});
这个包执行反应式连接,这实际上相当昂贵。所以请记住这一点,看看这对你来说是否仍然是一个好的选择


p、 我记得你不能在publish中使用Meteor.userId(),这就是我使用这个的原因。userId

关于你的问题(带标签的文章)的好处是,所有用户的关系都是一样的。因此,它是数据的属性,而不是数据请求的属性。所以你可以用反规范化来帮助你。在SQL世界中,您希望对所有数据进行规范化,然后在读取时使用联接将它们组合在一起。在MongoDB中,更好的方法是使用文档以非规范化的方式存储相关数据的子文档(因此您在另一个集合中拥有原始文档,并且在主文档中有一个副本作为子文档)。因为这些关系是数据的属性,所以您可以简单地嵌入这些子文档并将它们存储到主文档中

非规范化数据的问题是如何保持这些副本的同步。如何确保主文档更改后,子文档中的副本也会更新?为了解决这个问题,您可以使用Meteor包(我是作者之一),在该包中您可以声明一次关系,PeerDB将确保在文档更新后最终同步到一起

但是在您的例子中,问题是您想要隐藏
articles
数组本身中那些用户不应该看到的条目。这应该分别针对不同的用户。为此,您可以使用包(我也是作者之一),它允许您编写发布函数的此类转换

因此,我们的想法是:

  • 将ID和进行权限检查所需的信息反规范化到您的
    文章
    数组中
  • 然后,对于每次发布,删除用户不应有权访问的ID,并删除用于进行权限检查的额外字段
在咖啡脚本中:

class TagsToArticles extends Document
  @Meta
    name: 'TagsToArticles'
    fields: =>
      articles: [@ReferenceField Article, ['permission', 'ownerId']]

allTags = new PublishEndpoint 'allTags', ->
  TagsToArticles.documents.find {}

class CleanArticlesMiddleware
  processArticles: (fields, userId) ->    
    fields.articles = (_id for {_id, permission, ownerId} in fields.articles when permission is 'public' or ownerId is userId) if fields.articles

  added: (publish, collection, id, fields) ->
    @processArticles fields, publish.userId
    publish.added collection, id, fields

  changed: (publish, collection, id, fields) ->
    @processArticles fields, publish.userId
    publish.changed collection, id, fields

allTags.use new CleanArticlesMiddleware()

为什么不在每个文章文档中的数组中存储标记?那么一个包含该文章标签的字段
tags