dynamoose icon indicating copy to clipboard operation
dynamoose copied to clipboard

[BUG] - Unable to set nested array attribute as a non required property

Open idangabbay564 opened this issue 4 years ago • 10 comments

Summary:

I have a schema with an attribute of nested array containing external schema (field name is "teams"). I want to allow support for cases that there is no value to the attribute - in the form of blank array , null , empty attribute etc.

havent found a solution yet.

when trying to store an empty array, getting the following error:

"teams.0.name is a required property but has no value when trying to save document"

when trying to set the propery in the schema to {required: false}, and not passing any value as the prop, getting the following error:

"TypeError: node.forEach is not a function"

seems like it is always trying to scan through the array, also if it isnt required.

please help me to find a solution...

thanks in advance !

Code sample:

Schema

const innerTeamSchema = new dynamoose.Schema({
    name: { type: String, required: true },
    ref: { type: String, required: true },
    isPro: {
        type: Boolean,
        default: false
    },
    profileImageURL: {
        type: String,
        validate(value) { return validator.isURL(value.toString()) }
    },
    isManager: {
        type: Boolean,
        default: false
    }
}, { saveUnknown: false })


const schema = new dynamoose.Schema({
    PK: {
        type: String,
        hashKey: true,
        required: true,
        set(original) { return setKeys(ModelNames.PLAYERS, original.toString(), true) }
    },
    SK: {
        type: String,
        rangeKey: true,
        required: true,
        set(original) { return setKeys(ModelNames.PLAYERS, original.toString(), false) }
    },
    teams: { // nested array field
        type: Array,
        schema: [innerTeamSchema],
        required: false,
    }
}
    , {
        timestamps: true,
        saveUnknown: false
    })

Code sample

      const func = async () => {
    try {


        const player1 = new Player({
            PK: "shir@[email protected]",
            SK: "Profile",
            teams: [] // trying to save with a blank array
        })

        console.log(await player1.save()) // throws the following error: TypeError: node.forEach is not a function

        const player2 = new Player({ // trying to save without the team property (it isnt required)
            PK: "shir@[email protected]",
            SK: "Profile",
        })

        console.log(await player2.save()) // throws the following error: TypeError: node.forEach is not a function

    } catch (e) {
        console.log(e)
    }

}

func()

error stack trace

TypeError: node.forEach is not a function
    at D:\Users\USER\Documents\projects\mobile\full-stack\streetPro\StreetPro-BE\node_modules\dynamoose\lib\Document.ts:277:10
    at Array.forEach (<anonymous>)
    at traverse (D:\Users\USER\Documents\projects\mobile\full-stack\streetPro\StreetPro-BE\node_modules\dynamoose\lib\Document.ts:271:25)
    at D:\Users\USER\Documents\projects\mobile\full-stack\streetPro\StreetPro-BE\node_modules\dynamoose\lib\Document.ts:287:5
    at Array.forEach (<anonymous>)
    at traverse (D:\Users\USER\Documents\projects\mobile\full-stack\streetPro\StreetPro-BE\node_modules\dynamoose\lib\Document.ts:271:25)
    at Function.Document.attributesWithSchema (D:\Users\USER\Documents\projects\mobile\full-stack\streetPro\StreetPro-BE\node_modules\dynamoose\lib\Document.ts:293:2)
    at Function.Document.objectFromSchema (D:\Users\USER\Documents\projects\mobile\full-stack\streetPro\StreetPro-BE\node_modules\dynamoose\lib\Document.ts:383:4)
    at Document.toDynamo (D:\Users\USER\Documents\projects\mobile\full-stack\streetPro\StreetPro-BE\node_modules\dynamoose\lib\Document.ts:519:17)
    at async Promise.all (index 0)

dynamoose version : 2.7.3

Other:

  • [x] I have read through the Dynamoose documentation before posting this issue
  • [x] I have searched through the GitHub issues (including closed issues) and pull requests to ensure this issue has not already been raised before
  • [x] I have searched the internet and Stack Overflow to ensure this issue hasn't been raised or answered before
  • [x] I have tested the code provided and am confident it doesn't work as intended
  • [x] I have filled out all fields above
  • [x] I am running the latest version of Dynamoose

idangabbay564 avatar May 06 '21 18:05 idangabbay564

can someone please try to help me out here ? im trying to figure it out for a couple of days and doesnt manage to find a solution... @fishcharlie

idangabbay564 avatar May 08 '21 19:05 idangabbay564

@idangabbay564 Hoping to find time to look at this today or tomorrow. No guarantees tho. Been super busy lately.

fishcharlie avatar May 08 '21 21:05 fishcharlie

@idangabbay564 I was able to reproduce this. From what I can see right now, it does look like a bug.

My only workaround I can provide right now is to use saveUnknown and remove the teams property from your schema.

Hopefully I'll get around to fixing this soon, in the meantime if you wanna try to look at creating a PR that would be appreciated as well.


Note to self, below is an example to reproduce this:

const dynamoose = require("dynamoose");

(async () => {

	const innerTeamSchema = new dynamoose.Schema({
		name: { type: String, required: true },
		ref: { type: String, required: true },
		isPro: {
			type: Boolean,
			default: false
		},
		profileImageURL: {
			type: String,
			// validate(value) { return validator.isURL(value.toString()) }
		},
		isManager: {
			type: Boolean,
			default: false
		}
	}, { saveUnknown: false })


	const schema = new dynamoose.Schema({
		PK: {
			type: String,
			hashKey: true,
			required: true,
			// set(original) { return setKeys(ModelNames.PLAYERS, original.toString(), true) }
		},
		SK: {
			type: String,
			rangeKey: true,
			required: true,
			// set(original) { return setKeys(ModelNames.PLAYERS, original.toString(), false) }
		},
		teams: { // nested array field
			type: Array,
			schema: [innerTeamSchema],
			required: false,
		}
	}, {
		timestamps: true,
		saveUnknown: false
	})


	dynamoose.aws.ddb.local();

	const Player = dynamoose.model("Player" + Date.now(), schema);

	// const player1 = new Player({
	// 	PK: "shir@[email protected]",
	// 	SK: "Profile",
	// 	teams: [] // trying to save with a blank array
	// });

	// console.log(await player1.save()) // throws the following error: ValidationError: teams.0.name is a required property but has no value when trying to save document

	const player2 = new Player({ // trying to save without the team property (it isnt required)
		PK: "shir@[email protected]",
		SK: "Profile",
	})

	console.log(await player2.save()) // throws the following error: TypeError: node.forEach is not a function
})();

fishcharlie avatar May 09 '21 21:05 fishcharlie

hey @fishcharlie have you managed to find a solution ? tryed to look into the code and didnt go well...

idangabbay564 avatar May 22 '21 17:05 idangabbay564

@idangabbay564 Not yet. Still on my todo list. I was out of town all last week. Hoping to make time soon.

fishcharlie avatar May 24 '21 14:05 fishcharlie

hey @fishcharlie have you managed to look at the bug ?

idangabbay564 avatar Jun 30 '21 08:06 idangabbay564

Any update?

amitava82 avatar Aug 08 '21 03:08 amitava82

Hi,

i ran into the same error. The problem is the default-value for your properties "isPro" and "isManager" in your innerTeamSchema. If you try to save your player2 with an empty teams-array, the teams-array is not empty for dynamoose because the object to save looks something like this:

{
    "PK": "shir@[email protected]",
    "SK": "Profile",
    "teams": [
        {
            "isPro": false,
            "isManager": false
        }
    ]
}

Because the "name"-property in your innerTeamSchema is required an error is thrown.

As a workaround, I would recommend deleting the default values from your innerTeamSchema and assigning a default value programmatically.

Kind regards

koboldt avatar Jun 21 '22 08:06 koboldt

Any updates on this? We're running into this, but don't have default values in the nested schema.

slushman avatar Sep 29 '22 22:09 slushman

@slushman No updates. We use the 👍 voting system on the original issue to mark interest and priority. Currently this issue only has 1 👍 up vote. So its priority is fairly low.

PRs are welcome as always.

But in the meantime, there is a workaround by using saveUnknown, and it looks like the previous comment also mentioned removing the default value.

Any updates on this issue will be posted here.

fishcharlie avatar Sep 30 '22 03:09 fishcharlie