Even though attribute is unique:true, could someone comment why upsert still creates new and duplicate row when userid and username (both are not unique) are modified?


#1

in lib/collections.js:

Schemas.FutureTask = new SimpleSchema({
    number: {
        type: String,
        label: "TICKET_NUMBER",
        max: 10, //typically 10 digits
        index: true,
        unique: true
    },
     userid: {
        type: String,
        label: "USER_ID",
        max: 10 
    },
    username: {
        type: String,
        label: "ASSIGNED_TO",
        max: 50
    },

in server/main.js:

FutureTasks.upsert({
                    number: contentObj.records[i].number,
                    assignment_group: contentObj.records[i].assignment_group
                }, {
                    // Modifier
                    $set: {
                        userid: contentObj.records[i].assigned_to_userid,
                        username: contentObj.records[i].assigned_to,
                        start_date: myStartTime,
                        end_date: myModifiedEndTime
                    }
                }

I need to work with _id?


#2

You are also using collection2 and have attached the schema to the collection?


#3

Thanks Rob, yes I did. But I think I didn’t do meteor reset, now no duplicated rows as expected, but still getting:

Exception in callback of async function: Error: Future resolved more than once

Even though collection is updated correctly? Someone did mentioned setting flags but I just want to know why this is happening in the first place.


#4

Hmm. No idea - sorry - a quick Google of that error explains how it occurs (Fiber.return called more than once), but unless you know which package is causing it, it’s not really going to help much!


#5

Hi Rob

I think this exception came inside a for loop when I did a db.Collections.upsert with callback:

 for (var i = 0; i < recordsLength; i++) { 

 FutureTasks.upsert({
                    number: contentObj.records[i].number,
                    assignment_group: contentObj.records[i].assignment_group
                }, {
                    // Modifier
                    $set: {
                        start_date: modifiedStartTimeString,
                        end_date: modifiedEndTimeString
                    }
                }
               ,
              function (err, doc) {
                     if (err) {
                      console.log('error inside upsert : ', err.reason);
                        future.throw(err);
                  } else {
                      console.log('doc inside upsert : ', doc);
                      future.return(doc);
                   }
               }
            ); // End of insert
        } // End of 'ignore if null'
    } // End of for loop
   try {
             return future.wait();
        }
        catch (err) {
            throw new Meteor.Error("insert-error", err);
        }


   }

So how would one return a future inside a for loop? I guess we can’t do a for loop wrapping a function that returns s promise or future, but instead do something like promise.forEach etc?