Reputation: 22553
If I try to add some JSON that looks like this:
{ 'character.treasure_chests': 1 }
Mongoose barks with an error like this:
[Error: key character.treasure_chests must not contain '.']
Is this the expected behavior ?
Upvotes: 3
Views: 4775
Reputation: 236
I've run into this problem as well, and consider it a PITA as well when loading in data from sources you have little to no control over. There's a few workarounds, see below.
First off I'm going to assume that those dots aren't in your schema, right? In other words, you're inserting this JSON as part of a Mixed type which you have no control over. If you want to use dots in your schema, that's a whole different story, and something I'd avoid doing.
For allowing mongoose to deal with dotted keys in Mixed JSON though, there's at least two things you can do:
As others have suggested, simply escape the dots by replacing them with another character or character sequence, such as -
or -DOT-
. Of course, it does mean that if you have to map back to your original data, and you need to replace the -
or -DOT-
by a regular .
, you have to be damn sure that the original didn't have any -
's or -DOT-
's in there that would be replaced as well...
Also, it adds a pre-processing step in front of your database layer, which I try to avoid when possible.
I've actually noticed that mongoose only complains about this when creating new objects, like so:
let foo = new Foo({ data: {'character.treasure_chests': 1 }});
foo.save(); // results in Error: key character.treasure_chests must not contain '.'
However, when you update an existing document, it doesn't seem to complain about the dot:
let foo = new Foo({ data: {}});
await foo.save(); // first save the new object
foo.data = {'character.treasure_chests': 1 };
foo.save(); // no errors when updating the existing object!
Of course you need 2 calls to the database for this, making insert complexity effectively double, but at least you have dotted keys in mongodb!
Note that this might also have implications on the way you can query for those keys. But since this type of data is usually of the Mixed type, you can't do much structured querying there anyway.
Upvotes: 4
Reputation: 86
It's a valid JSON, but invalid Mongoose Schema. Since Mongoose' methods allow path navigation, if you have something like
{
'some.path': 'foo',
'some': {
'path': 'bar'
}
}
If not for this "shortcoming", method like document.get('some.path')
wouldn't know what to get.
It doesn't mean you cant use dots with mongoose ever. You can assign JSON as a value:
Schema = new mongoose.Schema({
'some': {
'path': {
'json': {} //any js object
}
}
})
Model = mongoose.model(Schema)
document = new Model()
document.some.path.json = {'inner.data': 'foo'}
Yo can access data via plain document.some.path.json['inner.data']
but you won't be able to use document.get()
with a path argument further than 'some.path.json'
since this schema path from Mongoose' perspective is terminal. You also will be limited in the way how you query such a field
All in all mongoose documents are based on JSON, but they are not supersets of it.
Upvotes: 2
Reputation: 22553
I'm pretty confident something like:
{"foo.com": 2}
is in fact valid JSON. The key is just a string.
http://jsonlint.com/ doesn't complain about it, and I can use it happily wherever I like, except when I try to assign it to a Mixed property in a mongoose schema (and a few other places).
You can see it work in this litlle fiddle: http://jsfiddle.net/gBgB6/1/
Sometimes, I'd like to store a value via a keypath {"foo.baz":0} that I want to use as a pointer to a key in a javascript object outside of the mongo document. I don't want to store it in nested form in mongo, but I also don't want to remap it like
{key:"foo.baz",
value: '0'
}
I think a few times I may have resorted to storing value in the table by mapping the dot(.) to another character.
It seems to me a short-coming in mongoose. I may ask after it :).
Upvotes: 4
Reputation: 2730
Yes, it is. Valid JSON doesn't have dots as far as I know. What you are supposed to do is this:
{
"character": {
"treasure_chests": 1
}
}
Here is an example: JSON Schema example
Upvotes: -1