Issue with subscribing to certain fields in Mongo Collection, crash when insert new document


#1

Here is the use scenario.

I have subscribed to a collection that only publishes certain fields from that collection. It is to cut down on network traffic.

If an insert is done on that collection with more fields than the publish is publishing to subscription, I get a crash loop in my WebApp.

I have also attempted to do this through a Meteor.method to see if I could work around this issue. It seems to not matter where this is coming from. Same issue occurs.

Anyone run into this?

Update:
I tried this from another WebClient as well and it will remotely crash the WebApp as well.

My guess is minimongo is expecting arrays or objects of certain length based on the initial subscription. When you insert something new into database then it freaks out, basically.

More info available:
This seems to be happening when having reactive data displayed. This is angular2 app, btw. Also, I tried to just insert the items being published. This also crashed the app. If I DO NOT restrict the amount of fields being published, this error does not occur.

Console:
Exception in queued task: TypeError: Cannot read property 'splice' of null at MongoCursorObserver._addAt (http://localhost:3000/packages/urigo_angular2-meteor.js?hash=7d95b1ebce5a649c724785bbd87a1b915643048e:264:31) at Object.addedAt (http://localhost:3000/packages/urigo_angular2-meteor.js?hash=7d95b1ebce5a649c724785bbd87a1b915643048e:236:47) at addedBefore (http://localhost:3000/packages/minimongo.js?hash=88217d643bc16fdf3505c6d4b2b8f5ddc400c49a:3699:28) at Object.addedBefore (http://localhost:3000/packages/minimongo.js?hash=88217d643bc16fdf3505c6d4b2b8f5ddc400c49a:3636:56) at http://localhost:3000/packages/minimongo.js?hash=88217d643bc16fdf3505c6d4b2b8f5ddc400c49a:410:13 at runTask (http://localhost:3000/packages/meteor.js?hash=ae8b8affa9680bf9720bd8f7fa112f13a62f71c3:721:11) at flush (http://localhost:3000/packages/meteor.js?hash=ae8b8affa9680bf9720bd8f7fa112f13a62f71c3:749:10) at drain (http://localhost:3000/packages/meteor.js?hash=ae8b8affa9680bf9720bd8f7fa112f13a62f71c3:757:12) at LocalCollection.insert (http://localhost:3000/packages/minimongo.js?hash=88217d643bc16fdf3505c6d4b2b8f5ddc400c49a:619:22) at Object.update (http://localhost:3000/packages/mongo.js?hash=ed0b13aca2f180af120dd0cfdba64ac79e2a624f:241:30)


#2

I think we need to see your code. As you’ve described it this is not expected behaviour.


#3

I can remove the fields and I do not get errors. This has to be on a page that has reactive variables being displayed. If variables are not being displayed, the error does not occur. If that helps any.

I appreciate the help!

import {AppointmentCollection} from 'collections/appointment_collection';
 
Meteor.publish('appointmentMinimal',function(){
    return AppointmentCollection.find({},{fields:{pName:1,active:1}});   
}); 

---------------------------------------------------------------------------------------------------------------------
/// <reference path="../../typings/angular2-meteor/angular2-meteor.d.ts" />
import {Page,NavController,NavParams} from 'ionic/ionic';
import {MeteorComponent} from 'angular2-meteor';
import {AppointmentCollection} from 'collections/appointment_collection';
import {NgFor} from 'angular2/common';
//Pages
import {Job} from 'client/pages/job';

@Page({
    templateUrl:'client/pages/jobs.html',
    directives:[NgFor]
})

export class Jobs extends MeteorComponent{

    private nav:NavController;
    private jobs:Mongo.Cursor<Object>;
    private jobDetails;
    private passedObj;
    private activeOnly=true;
    private hasEnumerated = false;

    private testCol;


    //Pages
    private job = Job;

    constructor(nav:NavController,params:NavParams){
        super();
        this.nav = nav;
        this.testCol = params.data.collection;        
        this.jobs = AppointmentCollection.find({active:this.activeOnly},{sort:{pName:1},fields:{pName:1,active:1}});
    }

    private openJob(_id){        
        this.nav.push(this.job,{_id:_id,jobCol:this.jobs});
    }

    private isActive(){
        if(this.activeOnly)
            this.jobs = AppointmentCollection.find({active:true},{sort:{pName:1}});
        else {
            this.jobs = AppointmentCollection.find({}, {sort: {pName: 1}});
        }
    }

-------------------------------------------------------------------------------------------------------

<ion-navbar *navbar>
    <ion-title>
        Projects
    </ion-title>
</ion-navbar>

<ion-content #content>
    <ion-row center>
        <ion-col width-75 class="full">Active Projects</ion-col>
        <ion-col width-25><ion-toggle secondary [(ngModel)]="activeOnly" [change]="isActive()" class="fr"></ion-toggle></ion-col>
    </ion-row>
    <ion-list>
        <button ion-item *ngFor="#j of jobs" (click)="openJob(j._id)">{{j.pName}}</button>
    </ion-list>
</ion-content>


<button fab fab-bottom fab-right style="z-index:99" (click)="openJob('')">
    <ion-icon name="add"></ion-icon>
</button>


#4

Are you simultaneously publishing more than once from the same collection with different fields specified? It may be that you are inadvertently causing a publication race condition following an insert.

There is a documented gotcha about that use case:

Currently, when multiple subscriptions publish the same document only the top level fields are compared during the merge. This means that if the documents include different sub-fields of the same top level field, not all of them will be available on the client. We hope to lift this restriction in a future release.


#5

I reformatted man and added more code.

Sorry about the crap post.

Actually, that is only one I’m doing now. I have had multiple, but at this time I’m only using that publication.


#6

Are you forgetting to call .fetch() on your cursor? I don’t use angular, so you might not have to do this.


#7

Fetch is if you want array. I don’t believe that will be reactive if you do.

Man, I appreciate any suggestions…


#8

Where is your subscription? Currently I don’t see how you are getting your published data.


#9

The sub is done the page before that,

It will just be re-subbing for no reason. This is in an ionic 2 app.

I have also tried with those fields in that sub.

The console.log() was to see what was coming back. And yes, it was just those fields…

 this.subscribe('appointmentMinimal',()=>{
            this.appointments = AppointmentCollection.find();
            console.log(this.appointments);
        },true);

#10

I’m stumped - not knowing angular probably isn’t helping. As the error looks like it rolls up from minimongo into angular code, it may just be quicker to ping @Urigo.


#11

Man, like I said thanks for any help!

I appreciate you taking the time out to have a look at it. Been trying to figure out ways to work around it, but I need that data loaded and reactive on that page. I could go around it some other way, I’m sure.


#12

How are you updating the collection? Are you using allow/deny and doing client-side update queries? Is there a chance that optimistic update of minimongo inserts the entire document, only to be invalidated by the publication which demands only 2 fields, leading to some sort of race condition not taken care of in the angular implementation?


#13

This is what I’m thinking, something along these lines.

I can either do a Meteor.call to a Meteor.method written to insert on server or just do an .insert on the collection client-side with same results.

Also as noted, you can do insert from another computer/mobile device/whatever and it will remotely crash the app(not on server, just in the client).

It seems as if the publication defines what the array of objects looks like on the client. But then that makes me wonder why would this only happen when displaying the reactive data on a page? Maybe there is some copy going on in minimongo to adjust the size and then destroy the previously allocated array of objects. This is causing angular code to go into a race condition since that object is no longer there, yet the angular code is trying to update your visual representation.

I believe this is strictly an angluar2 issue though.


#14

I would tend to think you’re right; I heavily abuse field projection specifiers and I’ve seen no such issue with Blaze or React.


#15

Whelp, I dug in @Urigo code over on github and looked in what was installed locally. I have figured out where in the code the error is happening. In master that part of code does not exist anymore, so I’m thinking maybe he has figured out there was an issue.

I guess just have to wait until update.

//New 
 private _addAt(doc, index) {
    let change = new AddChange(index, doc);
    return change;
  }
//Use to be
 private _addAt(doc, index) {
 -    this._docs.splice(index, 0, doc);
      let change = new AddChange(index, doc);
      return change;
    }

Hopefully this is the main culprit and it doesn’t go back any further.


#16

Hi everyone and sorry for the late response.
We were hard at work for updating to the latest Angular 2.0 stable.
Please try the new angular2-meteor@0.7.0, angular2-compilers@0.6.2_1 and the latest Angular 2.0.

We’ve update the Socially 2.0 tutorial and the Blaze to Angular 2 migration tutorial for reference - http://www.angular-meteor.com/migration/angular2/intro

Sorry for the long wait, it was very hard to keep up with Angular 2 releases in latest months.

If you find issues, please open new ones on the Github repo.


#17

Thanks man, I have been very busy myself.

Try and have a good one!