Meteor, MongoDB get part of an array via subscription

I have a question about how to simply get a specific element of an array using MongoDB and MeteorJS. I have the following schema for a custom document:

    bankList:[
       {
          id: "34567890987654345678",
          name: "xfgchjbkn",
          type: "credit"
       },
       {
          id: "09876543456789098767"
          name: "65789876t8",
          type: "debit"
       }
    ]

      

At first, I only subscribe to a subset of the fields in the array, in particular, I collect a list of all ids. Then I have an edit screen that needs to subscribe to all fields for a specific item in an array with the corresponding ID. I don't want to show the rest of the array with just one item. I am currently using the following to first collect a list of only ids:

   Meteor.users.find({_id: this.userId},
                        {fields:{'bankList.id': 1}});

      

And the following publish-subscribe method to get only specific information about an item:

Publication:

  Meteor.publish("userBankAdvanced", function(bankId){
      check(bankId,String);
      if(this.userId){
           return Meteor.users.find({_id:this.userId,"bankList.id": bankId}, {'bankList.$': 1});
      }else{
           this.ready();
      }
  });

      

Subscription:

  this.route('edit_account', {
        path: '/edit/account/',
        waitOn: function(){
              if(Session.get("bankId")){
                    return Meteor.subscribe('userBankAdvanced',Session.get("bankId"));
        }
        return null;
        },
        data: function(){
              if(Session.get("bankId")){
                return Meteor.users.findOne();
        }
        return null;
        },
        onBeforeAction: function(){
              beforeHooks.isRevise(Session.get("bankId"));
        }
  });

      

The subscription method returns all elements of the array with all information. I want, for example, only this (not the whole list with all the information):

       bankList:[
       {
          id: "34567890987654345678",
          name: "xfgchjbkn",
          type: "credit"
       }]

      

+3


source to share


2 answers


It looks like you just didn't specify the field specifier in your userBankAdvanced post function. I wrote a test in meteorpad using your example and it seems to be working fine. The bank ID is hardcoded for simplicity.

So instead of

return Meteor.users.find({_id:this.userId,"bankList.id": bankId}, {'bankList.$': 1});

      



try using

return Meteor.users.find({_id:this.userId,"bankList.id": bankId}, {fields: {'bankList.$': 1}});

      

+4


source


Unlucky, in Meteor, the "fields" option only works one level. In other words, there is no built-in way to include / exclude sub-document fields.

But all is not lost. You can always do it manually



Meteor.publish("userBankAdvanced", function (bankId) {
  var self = this;
  var handle = Meteor.users.find({
    _id: self.userId, "bankList.id": bankId
  }).observeChanges({
    added: function (id, fields) {
      self.added("users", id, filter(fields, bankId));
    },
    changed: function (id, fields) {
      self.changed("users", id, filter(fields, bankId));
    },
    removed: function (id) {
      self.removed("users", id);
    },
  });
  self.ready();
  self.onStop(function () {
    handle.stop();
  });
});

function filter(fields, bankId) {
  if (_.has(fields, 'bankList') {
    fields.bankList = _.filter(fields.bankList, function (bank) {
      return bank.id === bankId;
    });
  }
  return fields;
}

      

EDIT . I have updated the above code to match the requirements for the request. It turns out that Carlos' answer is also correct, and of course, it is much simpler, so I recommend using it.

+3


source







All Articles