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"
}]
source to share
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}});
source to share
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.
source to share