How to use watch() on web SDK?

Hello!

I’m trying to use the watch() method on the web SDK but it seems that it’s not documented anywhere yet. I made it working using this syntax but I still need to understand how to “close” the stream. Is there a standard way of closing these async iterators or it’s just not implemented yet?

const mongo = _app.services.mongodb("mongodb-atlas");
const mongoCollection = mongo.db("**project**").collection("**collection**").watch();

for await (const event of mongoCollection) {
      console.log("There is an event!", event)
}

It seems that @kraenhansen is the one working on it. Thank you.

I totally agree, we’re still missing a good example on using this.

Calling watch on a collection returns an AsyncIterable (an object with the Symbol.asyncIterator property). More specifically watch is an async generator function, which means that the iterable it returns is also a Generator: Calling the return() method on this will break the loop and close the underlying connection.

If you have opinions about this API, I encourage you to voice it on Alternative MongoDB Watch API · Issue #3259 · realm/realm-js · GitHub and https://twitter.com/kraenhansen/status/1313136226246053890.

1 Like

@kraenhansen I read that post. In my opinion, it should be more similar to the realm react-native implementation (so just call subscribe( callback ) ) but if it works it works.

UPDATE

I’m using something like that right now

class DB {
   
    static stream = async (myEventEmitter:any, mongoCollectionWatch:any, mongoCollectionFind:any) => {

    
        
    for await (const event of mongoCollectionWatch) {
        myEventEmitter.emit('testEvent', {
            event : event,
            data: await mongoCollectionFind.find()
        }); // Was fired: hi
    }

}

static watchLikes = async () => {

    const mongo = J.Auth._app.services.mongodb("mongodb-atlas");
    const mongoCollectionFind = mongo.db("Project_1").collection("likes");
    const mongoCollectionWatch = mongo.db("Project_1").collection("likes").watch();
    const myEventEmitter = new MyEventEmitter();

    Db.stream(myEventEmitter, mongoCollectionWatch, mongoCollectionFind)

    return { on : async (callback:any)=>{ 
            var on =  myEventEmitter.on('testEvent', callback) 
            myEventEmitter.emit('testEvent', {
                event : "FIRST_CALL",
                data: await mongoCollectionFind.find()
            });
            return on
        }, removeListener : (callback:any) => { 
        mongoCollectionWatch.return() 
        myEventEmitter.removeListener("testEvent", callback ) 
    } }

}

    ...
}

Event emitter (found here How to Create Your Own Event Emitter in JavaScript | by Oleh Zaporozhets | Better Programming)

class MyEventEmitter {

    _events:any

    constructor() {

      this._events = {};

    }

  

    on(name:string, listener:any) {

      if (!this._events[name]) {

        this._events[name] = [];

      }

  

      this._events[name].push(listener);

    }

  

    removeListener(name:string, listenerToRemove:any) {

      if (!this._events[name]) {

        throw new Error(`Can't remove a listener. Event "${name}" doesn't exits.`);

      }

  

      const filterListeners = (listener:any) => listener !== listenerToRemove;

  

      this._events[name] = this._events[name].filter(filterListeners);

    }

  

    emit(name:string, data:any) {

      if (!this._events[name]) {

        throw new Error(`Can't emit an event. Event "${name}" doesn't exits.`);

      }

  

      const fireCallbacks = (callback:any) => {

        callback(data);

      };

  

      this._events[name].forEach(fireCallbacks);

    }

  }

This way I can easily do this:

<button onClick={async ()=>{

   likes = await J.Db.watchLikes()

   likes.handle = (data:any)=>{

        console.log("Event", data)

    }

   likes.on(likes.handle)
}}>

 Watch likes

</button>

<button onClick={async ()=>{

 try {

      likes.removeListener(likes.handle)

 } catch (error) {

       console.log("Errore", error)

}

}}>

 Unwatch likes

I’m sure this could be written in a simpler way but in my current stage it’s “ok”. Of course it could be nice to have this “event emitter” implementation in the SDK

3 Likes