0

I have this model in Mongoose and NodeJS:

const VisitorSchema = new Schema({
  visits: [{date: Date, path: String, details: String}],
  // ...
});

And this code:

// Get all visitors.
VisitorSchema.statics.getAllVisitors = function() {
  try {
    // Return all users.
    return Visitor.find()
      .sort({created: -1})
      .exec();
  } catch (err) {
    console.log(err);
  }
};

// Check and print new users.
VisitorSchema.statics.checkPaths = async function() {
  console.log("Checking paths...");
  let visitors = await this.getAllVisitors();
  for (let visitor of visitors) {
    try {
      for (let v of visitors.visits) {
        // ...
      }
    } catch (e) {
      console.log(e);
      console.log(Object.prototype.toString.call(visitor.visits));
      throw(e);
    }
  }
};

Running this function unexpectedly throws:

Checking paths...
TypeError: visitors.visits is not iterable
    at Function.VisitorSchema.statics.checkPaths
[object Array]
5efba3a0a97a823909802df5
(node:23663) UnhandledPromiseRejectionWarning: TypeError: visitors.visits is not iterable
    at Function.VisitorSchema.statics.checkPaths 
    at processTicksAndRejections
    ....

I also checked the MongoDB object in the mongo shell and the sub-document visits for the relevant document is an array and seems OK:

> db.visitors.findOne({_id: ObjectId("...")})
{
    "_id" : ObjectId("..."),
    "visits" : [
        {
            "_id" : ObjectId("..."),
            "date" : ISODate("..."),
            "path" : "/"
        },
        ...
    ]
}

How can an Array object not be iterable?

6
  • 1
    Shouldn't getAllVisitors be declared as async (VisitorSchema.statics.getAllVisitors = async function() { ... })? Commented Dec 14, 2020 at 11:10
  • 4
    You're referencing the wrong variable in your 2nd inner for loop. for (let v of visitors.visits) should probably be for (let v of visitor.visits). Commented Dec 14, 2020 at 11:12
  • 1
    @Sven You are correct and that fixed it. Can you write an answer, emphasizing that all array objects are iterable, and if they're not, the bug is elsewhere? Commented Dec 14, 2020 at 11:17
  • 3
    @Sven is correct @miguelmorin, however, you can also try this visitors.forEach( ( v ) => { console.log(v.visits.id) }) Commented Dec 14, 2020 at 11:25
  • 1
    @secan Only if the OP meant to return await Visitor.find().…; Commented Dec 14, 2020 at 14:10

1 Answer 1

1

An array is always iterable in JS. Pay attention to the rows in the visitors collection, which may lack the visits property. If that property is not an array in MongoDB (this is allowed because MongoDB is a NoSQL database) it will still be cast to an empty array from your model definition.

In your specific case, you have a typo:

for (let v of visitors.visits) // plural

should probably be

for (let v of visitor.visits) // singular
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.