从嵌套数组中提取/删除项目

时间:2018-03-29 20:38:36

标签: mongodb meteor

注意:这是一个流星项目。 我的架构看起来像这样:

{
    _id: 'someid'
    nlu: {
       data: {
            synonyms:[
                 {_id:'abc', value:'car', synonyms:['automobile']}
            ]
       }
    }
}

架构使用simple-schema定义。相关部分:

 'nlu.data.synonyms.$': Object,
    'nlu.data.synonyms.$._id': {type: String, autoValue: ()=> uuidv4()},
    'nlu.data.synonyms.$.value': {type:String, regEx:/.*\S.*/},
    'nlu.data.synonyms.$.synonyms': {type: Array, minCount:1},
    'nlu.data.synonyms.$.synonyms.$': {type:String, regEx:/.*\S.*/},

我正在尝试删除{_id:'abc'}

Projects.update({_id: 'someid'},
                {$pull: {'nlu.data.synonyms' : {_id: 'abc'}}});

查询返回1(一个文档已更新)但该项目未从数组中删除。有什么想法吗?

2 个答案:

答案 0 :(得分:0)

这是我的插入查询

db.test.insert({
    "_id": "someid",
    "nlu": {
       "data": {
            "synonyms": [
                 {
                    "_id": "abc"
                 },
                 {
                    "_id": "def"
                 },
                 10,
                 [ 5, { "_id": 5 } ] 
            ]
       }
    }
})

这是我的更新

db.test.update(
    {
      "_id": "someid",
      "nlu.data.synonyms._id": "abc"
    },  
    {
      "$pull": {        
        "nlu.data.synonyms": {
          "_id": "abc"
        }
      }
    }
)

答案 1 :(得分:0)

问题分解为autoValue媒体资源上的_id参数。

这是a very powerful feature来操作架构上的自动值。但是,由于它始终返回一个值,因此无法拉动,表示应该设置此字段。

为了让它知道拉动,你可以让它知道存在operator(如mongo更新的情况)。

您的autoValue将如下所示:

'nlu.data.synonyms.$._id': {type: String, autoValue: function(){
  if (this.operator) {
    this.unset();
    return;
  }
  return uuidv4();
}},

编辑:注意这里的函数不是箭头函数,否则会丢失SimpleSchema上绑定的上下文。

当没有操作符存在时(如插入操作中),它基本上只返回一个新的uuid4。您可以根据需要通过提供的功能(请参阅文档)进一步扩展此功能。

我只是将我的代码汇总为可重现的示例:

import uuidv4 from 'uuid/v4';

const Projects = new Mongo.Collection('PROJECTS')

const ProjectSchema ={
  nlu: Object,
  'nlu.data': Object,
  'nlu.data.synonyms': {
    type: Array,
  },
  'nlu.data.synonyms.$': {
    type: Object,
  },
  'nlu.data.synonyms.$._id': {type: String, autoValue: function(){
    if (this.operator) {
      this.unset();
      return;
    }
    return uuidv4();
  }},
  'nlu.data.synonyms.$.value': {type:String, regEx:/.*\S.*/},
  'nlu.data.synonyms.$.synonyms': {type: Array, minCount:1},
  'nlu.data.synonyms.$.synonyms.$': {type:String, regEx:/.*\S.*/},
};

Projects.attachSchema(ProjectSchema);

Meteor.startup(() => {

  const insertId = Projects.insert({
    nlu: {
      data: {
        synonyms:[
          {value:'car', synonyms:['automobile']},
        ]
      }
    }
  });

  Projects.update({_id: insertId}, {$pull: {'nlu.data.synonyms' : {value: 'car'}}});

  const afterUpdate = Projects.findOne(insertId);
  console.log(afterUpdate, afterUpdate.nlu.data.synonyms.length); // 0
});

可选替代方法:规范化集合

然而,还有一个额外的优化说明。

您可以通过将同义词规范化为自己的集合来解决此auto-id生成问题,其中mongo insert为您提供了id。我不确定这个ID与uuidv4相比有多独特,但我从未遇到过id问题。

设置可能如下所示:

const Synonyms = new Mongo.Collection('SYNONYMS');

const SynonymsSchema  = {
  value: {type:String, regEx:/.*\S.*/},
  synonyms: {type: Array, minCount:1},
  'synonyms.$': {type:String, regEx:/.*\S.*/},
};

Synonyms.attachSchema(SynonymsSchema);

const Projects = new Mongo.Collection('PROJECTS')

const ProjectSchema ={
  nlu: Object,
  'nlu.data': Object,
  'nlu.data.synonyms': {
    type: Array,
  },
  'nlu.data.synonyms.$': {
    type: String,
  },
};

Projects.attachSchema(ProjectSchema);

Meteor.startup(() => {

  // just add this entry once
  if (Synonyms.find().count() === 0) {
    Synonyms.insert({
      value: 'car',
      synonyms: ['automobile']
    })
  }

  // get the id
  const carId = Synonyms.findOne()._id;

  const insertId = Projects.insert({
    nlu: {
      data: {
        synonyms:[carId] // push the _id as reference
      }
    }
  });

  // ['MG464i9PgyniuGHpn'] => reference to Synonyms document
  console.log(Projects.findOne(insertId).nlu.data.synonyms); 

  Projects.update({_id: insertId}, {$pull: {'nlu.data.synonyms' : carId }}); // pull the reference

  const afterUpdate = Projects.findOne(insertId);
  console.log(afterUpdate, afterUpdate.nlu.data.synonyms.length);
});

我知道这不是问题的一部分,但我只想指出将复杂文档结构规范化为单独的集合有很多好处:

  • 没有重复数据
  • 解耦非意图绑定的数据(此处:同义词也可以独立于项目使用)
  • 更新引用文档一次,所有项目都将指向实际版本(因为它是参考)
  • 更精细的出版物/订阅处理=>更多地控制通过电线传输什么数据
  • 减少复杂的自动和默认值生成
  • 引用集合模式中的更改对于使用引用者模式的UI和函数可能只有很少的影响。

当然这也有缺点:

  • 要处理的更多馆藏
  • 要编写更多代码(更多代码=更多潜在错误)
  • 写更多测试(投入更多时间)
  • 有时你需要对100个
  • 中的这一个案例进行非规范化
  • 在开始编码之前,你必须在数据模式设计上投入大量时间