45

In my Mongoose schema, I have a field which is a String, and I want to be able to store an JSON object in it. Is it possible? In Postgres, it's possible to store a dictionary in a string column.

I want to do that because the dictionary (actually a JSON object in JS) is just a simple read and write value and doesn't need queries, but also, because it is just one value and not an array of values.

5 Answers 5

128

Yes, you can just store {myJsonProperty: JSON.stringify(myObject)}. Hopefully you know that you can also just set {myJsonProperty: Object} in your mongoose schema and store the whole object without converting it to a string for no reason. It doesn't have to be a nested document with a schema, it can be just a plain javascript object.

Sign up to request clarification or add additional context in comments.

5 Comments

I can just store a object? Are you sure? That would be ideal for me but Mongoose Docs doesn't mention that type.
Yes. You can also use the Mixed type if you want a true anything-goes property. github.com/LearnBoost/mongoose/blob/3.6.14/lib/schema/mixed.js
Should I use mixed or object. Basically I want to store a JSON object. So what would be better?
Object is more accurate. You really only need Mixed if you want some documents to have an Array, others to have Object, others to have String, etc, etc.
@PeterLyons Mixed and Object are the same and can be used interchangeably - see docs where it says 'The following are equivalent': mongoosejs.com/docs/schematypes.html#mixed
22

if you can change the type of your field form "String" to "Object" you can save the json as it is.

var schema_obj = new Schema({
field1: Object,
..
});

Comments

20

The accepted answer is good for the majority of situations.

However, if you have an object which you want to store, and you have no control over the object keys (e.g. they might be user-submitted), you might want to consider storing these as stringifed JSON. This allows you to overcome the limitation imposed by MongoDB that keys must not contain the reserved characters $ or ..

You can achieve this using Mongoose getters and setters, for example:

data: {
  type: String,
  get: function(data) {
    try { 
      return JSON.parse(data);
    } catch(error) { 
      return data;
    }
  },
  set: function(data) {
    return JSON.stringify(data);
  }
}

Comments

6

Couldn't alter the original due to the 6 change limit on stack-overflow. re-posted, awesome work Tom, was just missing catch(err) in the catch block

data: {
  type: String,
  get: function(data) {
    try { 
      return JSON.parse(data);
    } catch(err) { 
      return data;
    }
  },
  set: function(data) {
    return JSON.stringify(data);
  }
}

Comments

1

We needed to retain structure and not do a string so I came up with the following methods to handle this:

const setMongoMixedWithBadKeys = data =>
  Array.isArray(data)
  ? data.map(setMongoMixedWithBadKeys)
  : typeof data === 'object' 
  ? Object.entries(data).reduce((a, [key,value])=>({...a, [key.replace('.','__').replace('$','___')]:setMongoMixedWithBadKeys(value)}), {})
  : data

const getMongoMixedWithBadKeys = data =>
  Array.isArray(data) 
  ? data.map(getMongoMixedWithBadKeys) 
  : typeof data === 'object'
  ? Object.entries(data).reduce((a, [key, value])=> ({...a, [key.replace('__','.').replace('___','$')]:getMongoMixedWithBadKeys(value)}), {})
  : data


data: {
  type: Mixed,
  get:  getMongoMixedWithBadKeys,
  set:  setMongoMixedWithBadKeys
}

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.