Edit an element within an object, within an array, with Mongoose

2

I need a help! I'm new to Node.JS and I decided to "create a system" to put into practice what I already know and create challenges to encourage my learning! I did a beginner workshop (with Jean Carlo Suissa) that gave me a good foundation, but I need "something more"!

I've researched a lot, but I still can not solve the problem below:

Schema

Company

, ativa: {type: Boolean, default: true}
, prestacao_servico:
  [ { inicio: {type: Date, default: Date.now, trim: true}
  , fim: {type: Date, default: '', trim: true}
    }
  ]

Whenever a contract is renewed or the company is registered, an element will be inserted into the service_server array by determining the start date strong> of this agreement, with the end field having null value and the active boolean will be set to true . And when the company is deactivated it should be searching within the array service_server the item that has the null field (only if there is an item of this timestamp in the array) and change its value to the closing date Date.now() , the active value should also be set to false .

Example:

{
  "_id": "54eec2379881c0d032856dd5",
  "razao_social": "Empresa 1 EIRELI me",
  "__v": 3,
  "contato": {
    "telefone": "1212341234",
    "celular": "12123451234",
    "email": "[email protected]"
  },
  "endereco": {
    "cep": "12345123",
    "logradouro": "Rua A",
    "bairro": "Bairro A",
    "cidade": "Cidade 1",
    "uf": "RJ",
    "pais": "Brasil",
    "complemento": "",
    "numero": "123"
  },
  "simples_nacional": {
    "codigo": "123412341234"
  },
  "documentos": {
    "cnpj": "12123123123412",
    "inscricao_estadual": "12345678"
  },
  "opcao": {
    "sociedade": 1,
    "enquadramento": 1,
    "tributacao": 2
  },
  "prestacao_servico": [
    {
      "_id": "54eec2379881c0d032856dd6",
      "fim": "2015-02-26T07:06:14.741Z",
      "inicio": "2015-01-08T21:00:00.000Z"
    },
    {
      "_id": "54eec305f32a497533dc8eb1",
      "fim": "2015-02-26T07:08:42.451Z",
      "inicio": "2015-02-26T06:53:57.543Z"
    },
    {
      "_id": "54eec7505b3f2dd13688589d",
      "fim": null,
      "inicio": "2015-02-26T07:12:16.775Z"
    }
  ],
  "ativa": true
}

The above company is active ( "ativa": true ) and had your contract started right now 2015-02-26T07: 12: 16.775Z . When you disable it, the end field of the object whose _id is 54eec7505b3f2dd13688589d should receive the value corresponding to the "timing of the deactivation."

Problem:

How to find the company (by _id ), then find the item (in service_server ) that has end null and edit it by entering the moment? I have already used the query {_id: req.params.id, prestacao_servico: {$elemMatch: {fim: null}}} within find , but using $elemMatch makes no difference since it will not have another company with the same ID, even why the documentos.cnpj field is set to unique. The aggregate returned no result.

I've got a solution, but it seems to me to be a great gambiarra:

_Model.findOne({_id: req.params.id, "prestacao_servico.fim": null}, function(err, data){
  if(err) {
    // ERRO
  }
  var count = 0
  , i
  ;
  data.prestacao_servico.forEach(function(element, index, array) {
    if(element.fim === null) {
      count++;
      i = index;
    }
  });
  if(count > 1) {
    // ERRO
  }
  else {
    data.prestacao_servico[i].fim = Date.now();
    data
    .save(function(e, d) {
      if(err) {
        // ERRO
      }
      else {
        // DATA
      }
    });
  }
});

Any tips?

SOLUTION

I followed my reasoning, applied the improvements quoted by Sergio and tried to improve some aspects, too. Finally, it ended like this:

  var dados = req.params
    , query = {_id: dados.id}
    ;
  var promise = _Model.findOne(query).exec();
  promise
    .then(function(e) {
      ps = e.prestacao_servico.filter(function(item) {
        return !item.fim;
      });
      if(ps.length !== 1) throw new _SigError();
      ps[0].fim = Date.now();
      e.save();
      return e;
    })
    .then(function(data) {
      cb(null, data, res);
    })
    .then(null, function(err) {
      cb(err, null, res);
    });
    
asked by anonymous 04.03.2015 / 02:21

1 answer

2

I think it really has to be that way. I suggest a little change in the code but basically your idea is right:

_Model.findOne({_id: req.params.id, "prestacao_servico.fim": null}, function(err, data){
    if(err) {
        return 'Erro!'; // é importante dar return aqui para não continuar
    }
    var ativos = data.prestacao_servico.filter(function(ps){
        return !ps.fim; // assumindo que tem null e não "null" (string)
    });
    if (ativos.length > 1) return 'Erro! Há mais que um registo ativo!';
    if (!ativos) return 'Erro! Todos os registos estão fechados!';
    ativos[0].fim = Date.now();
    data.save(function(err, data) { // repara que aqui tinhas "(e, d)" mas em baixo usas "err" e não "e"
      if(err) { 
        // ERRO
      }
      else {
        // OK, dar confirmação ao usuário
      }
    });
});

Another option is to use findOneAndUpdate([query], [doc], [options], [callback]) , but the code inside callback is identical.

    
04.03.2015 / 08:50