Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pull an entry from an array via Meteor

I've the following (simplified) SimpleSchema schema in my Meteor 1.1.0.2 app:

Tickers.attachSchema(
    new SimpleSchema({
        entries: {
            type: [TickerEntries],
            defaultValue: [],
            optional: true
        }
    })
);

TickerEntries = new SimpleSchema({
    id: {
        type: String,
        autoform: {
            type: "hidden",
            label: false,
            readonly: true
        },
        optional: true,
        autoValue: function () {
            if (!this.isSet) {
                return new Mongo.Collection.ObjectID()._str;
            }
        }
    },
    text: {
        type: String,
        label: 'Text'
    }
};

In the database I do have the following entries:

{
    "_id" : "ZcEvq9viGQ3uQ3QnT",
    "entries" : [
        {
            "text" : "a",
            "id" : "fc29774dadd7b37ee0dc5e3e"
        },
        {
            "text" : "b",
            "id" : "8171c4dbcc71052a8c6a38fb"
        }
    ]
}

I'd like to remove one entry in the entries array specified by an ID.

If I execute the following command in the meteor-mongodb-shell it works without problems:

db.Tickers.update({_id:"3TKgHKkGnzgfwqYHY"}, {"$pull":{"entries": {"id":"8171c4dbcc71052a8c6a38fb"}}})

But the problem is, that if I'm going to do the same from within Meteor, it doesn't work. Here's my code:

Tickers.update({id: '3TKgHKkGnzgfwqYHY'}, {$pull: {'entries': {'id': '8171c4dbcc71052a8c6a38fb'}}});

I've also tried the following:

Tickers.update('3TKgHKkGnzgfwqYHY', {$pull: {'entries': {'id': '8171c4dbcc71052a8c6a38fb'}}});

None of these commands give me an error, but they don't remove anything from my document.

Could it be possible, that the $pull command isn't supported properly or do I have made a mistake somewhere?

Thanks in advance!

EDIT: I've found the problem, which couldn't be seen in my description, because I've simplified my schema. In my app there's an additional attribute timestamp in TickerEntries:

TickerEntries = new SimpleSchema({
    id: {
        type: String,
        optional: true,
        autoValue: function () {
            if (!this.isSet) {
                return new Mongo.Collection.ObjectID()._str;
            }
        }
    },
    timestamp: {
        type: Date,
        label: 'Minute',
        optional: true,
        autoValue: function () {
            if (!this.isSet) { // this check here is necessary!
                return new Date();
            }
        }
    },
    text: {
        type: String,
        label: 'Text'
    }
});

Thanks to the hint from Kyll, I've created a Meteorpad and found out, that the autovalue function is causing the problems.

I've now changed the function to the following code:

autoValue: function () {
    if (!this.isSet && this.operator !== "$pull") { // this check here is necessary!
        return new Date();
    }
}

And now it is working. It seems, that returning a autovalue-value in the case of pulling an item/object, it cancels the pull operation, as the value isn't set to the returned value (so the timestamp attribute keeps the old value but isn't pulled).

Here's the according Meteorpad to test it (simply comment out the check for the operator in the autovalue function): http://meteorpad.com/pad/LLC3qeph66pAEFsrB/Leaderboard

Thank you all for your help, all your posts were very helpful to me!

like image 379
reini122 Avatar asked Aug 06 '15 10:08

reini122


1 Answers

For a basic meteor application, I call "bunk" on this. If you create a brand new project and simply define the collection, then the $pull operator works as expected:

Console:

meteor create tickets
cd tickets
meteor run

Then open up a shell and insert your data:

meteor mongo

> db.tickets.insert(data)   // exactly your data in the question

Then just produce some basic code and template:

tickers.js

Tickers = new Meteor.Collection("tickers");

if (Meteor.isClient) {

  Template.body.helpers({
    "tickers": function() {
      return Tickers.find({});
    }
  });

}

if (Meteor.isServer) {
  Meteor.startup(function () {
    // code to run on server at startup
  });
}

tickers.html

<head>
  <title>tickers</title>
</head>

<body>
  <h1>Welcome to Meteor!</h1>

  <ul>
    {{#each tickers}}
      {{> ticker}}
    {{/each}}
  </ul>

</body>

<template name="ticker">
  <li>
    {{_id}}
    <ul>
      {{#each entries}}
        {{> entry }}
      {{/each}}
    </ul>
  </li>
</template>

<template name="entry">
  <li>{{ id }} - {{text}}</li>
</template>

The application should be running fine, so in your browser console do the .update() (indented for reading):

Tickers.update(
    { "_id": "ZcEvq9viGQ3uQ3QnT" },
    { "$pull": { "entries": { "id": "fc29774dadd7b37ee0dc5e3e" } }}
)

And the item is removed from entries and the page is refreshed without the item. So all gone, just as expected.

Even adding the SimpleSchema and Collection2 packages, makes no difference here:

 meteor add aldeed:simple-schema
 meteor add aldeed:collection2

tickers.js

Tickers = new Meteor.Collection("tickers");

TickerEntries = new SimpleSchema({
  "id": {
    type: String,
    optional: true,
    autoValue: function() {
      if (!this.isSet) {
        return new Mongo.Collection.ObjectID()._str
      }
    }
  },
  "text": {
    type: String
  }
});

Tickers.attachSchema(
  new SimpleSchema({
    entries: { type: [TickerEntries] }
  })
);


if (Meteor.isClient) {

  Template.body.helpers({
    "tickers": function() {
      return Tickers.find({});
    }
  });

}

if (Meteor.isServer) {
  Meteor.startup(function () {
    // code to run on server at startup
  });
}

Re-initialize the data and run the same command in the browser console and everything stays the same.

Check this or any typing mistakes in your own operations or other differences for a clue as to why this does not work for you.

I would suggest this strongly, as "starting fresh" like this shows the expected behavior, and if you are seeing different behavior then it is likely an issue with another plugin you have installed.

But generally, this works.

like image 163
Blakes Seven Avatar answered Sep 28 '22 11:09

Blakes Seven