This is the mongo schema-
{
name: String
description: String,
array1: [{prop1: Number, prop2: String}],
referencingArray: {prop1: String, prop2_array1ref: <array1 element ref>},
}
Array elements of type object. One of the properties in referencingArray object need to refer to an element from array1. The UI will later use the referenced array element to annotate referencingArray info. The UI also needs to update referencingArray based on changes to array1. Currently array1 objects do not have any uniquely identifying property.
One idea I have is to add a guid property to array1 objects to uniquely identify them and make the referencingArray object's prop2_array1ref to use this guid. But that adds an extra property on the array1 objects.
Referring to array1 objects via index will need to handle delete from array1. If prop2_array1ref is referring to index 0 element of array1, deleting the element at index 0 should put referencingArray in a bad state instead of silently referring to the new object at index 0.
Mongo assigns _id property to array objects. I thought of using the _id property of array objects in prop2_array1ref but I am not sure how to handle new entries when the array objects don't have an id yet.
Question:
What's the best way to refer array1 elements from referencingArray?
Edit to add example:
{
name: 'John',
description: 'Best guy',
array1: [
{prop1: 12, prop2: 'lorem'},
{prop1: 55, prop2: 'ipsum'}
],
referencingArray: {prop1: 'domur', prop2_array1ref: <array1 element 1 ref>},
// User can change prop2_array1ref to point to different element of array1 in UI.
// Question is what's a good value for prop2_array1ref?
// Options are-
// 1. Add guid to array1 elements and use that as value of prop2_array1ref. (e.g. 'fl3-42mnj-348hn-83ngns')
// 2. index of array1 elements. (e.g. 1)
// 3. mongo assigned _id of array1 elements. (e.g. 98702398420398)
}
A simple normalization will do the job:
your main model
{
name: String
description: String,
array1: [{type: Schema.Types.ObjectId, ref: 'Array1Model'}],
referencingArray: {prop1: String, prop2_array1ref: {type: Schema.Types.ObjectId, ref: 'Array1Model'}},
}
Array1Model
{
prop1: Number
prop2: String
}
As you said yourself, mongo will implicitly add the primary key. Later on, if you want to render them nicely on the frontend, you do a simple "join"-like operation using $lookup. Here's an example.
Related
How to create a unique ID for each element of an array field, where uniqueness is maintained globally for all documents of the collection?
Is it possible to specify create a unique index for this field?
You can make use of ObjectId data type. ObjectIds are 12-byte values that are guaranteed to be unique across all documents in a collection. You can specify an ObjectId as the value for a field in an array when inserting a new document.
For example, if you have following document:
{
_id: ObjectId("5f9b5a6d65c5f09f7b5a6d65"),
nameOfArrayField: []
}
You can use the following command to insert a new document:
db.collection.insertOne({
nameOfArrayField: [
{
id: new ObjectId(),
name: "Big Cat Public Safety Law"
}
]
});
To specify a unique index, you can use createIndex() method in the MongoDB shell.
db.collection.createIndex({ "nameOfArrayField.id": 1 }, { unique: true })
unique: true option ensures that the id field of the element array will be unique globally for all documents of the collection. It will prevent from inserting the duplicate element with the same id field in the array. Point to be noted that it is an asynchronous operation. You can use the db.collection.getIndexes() method to check if the index is created or not.
I have a problem, deciding how to design my data model for later easy querying and extracting of field values...
The thing is, I use the MEAN stack and I have two collections in my MongoDB database: FA and FP.
var FASchema = new Schema({
Timestamp: Date,
ProgBW: Number,
posFlexPot: Number,
negFlexPot: Number,
Leistungsuntergrenze: Number,
Leistungsobergrenze: Number,
posGesEnergie: Number,
negGesEnergie: Number,
Preissignal: Number,
Dummy1: Schema.Types.Mixed,
Dummy2: Schema.Types.Mixed,
Dummy3: Schema.Types.Mixed
//same: Dummy: {}
});
var FPSchema = mongoose.schema( {
_id: { type: String },//mongoose.Schema.Types.ObjectId,
Demonstrator: Number,
erstellt: {type: Date, 'default': Date.now},
von: Date,
bis: Date,
FAs: [{type: mongoose.Schema.Types.ObjectId, ref: "FA"}]
})
First question here, is it possible to automatically create _id fields as Strings, because I heard it should be easier to query for id's as strings later..
Second question: my FP schema contains instances (or rather subdocuments as plain text) inside the field "FAs" (How exactly this is done, is a later topic). My question is, should I draft that field as an array of documents
[{FAinstance1.field1value, FAinstance1.field2.value},{FAinstance2.fiel1.value,...}]
with lots of FA documents, or should I do something like this (document of documents of arrays:
{FA.field1: [valueFA1, valueFA2,..], FA.field2: [value2FA1, value2FA2,..],...}
Because for each "FA" document, I later want to extract some values from fields like Timestamp, negGesEnergie, etc. and do this for every FA instance in the list. I extract them either from a mongoDB or directly from a API (e.g POST request).
Because I want to plot the values later in some chart (written in javascript), where every FA1_instance.x1 value and FA2_instance.x1 value (coming sequentially in the list) represents the numbers on the x-axis, and other fields are the sequence of numbers for the y-values (which are the values of the sequences of FA instances in the list) accordingly.
What would be the easiest data model to extract the values for each FA instance field later on?
Can you tell me when array of documents should be used and when array of objects should be used ?
By array of objects I'm assuming you mean ObjectId's AKA references to other collections, since a document is just a JSON object anyway.
The basic paradigm of data modeling is to embed whenever possible. If your collection references a finite number such a user's list of phone numbers like this - you definitely want to embed.
{
phone_numbers: [
{
type: "mobile",
number: "(123)456-7890"
},
{
type: "home",
number: "(456)789-0123"
}
]
}
If you are referencing a 1 <--> Many or 1 <--> Very Many collection, that is when you want to use references such as messages sent/received to a user.
{
from: ObjectId, // Reference to ObjectId of the sender
to: [], // Array of ObjectId references
message: String,
date: Date
}
I highly advise reading here:
https://docs.mongodb.com/v3.2/core/data-model-design/
In the algolia documentation, they specify that you can manipulate arrays like this:
// adding
index.partialUpdateObject({
myfield: {
value: 'myvalue',
_operation: 'Add'
},
objectID: 'myID'
})
/removing
index.partialUpdateObject({
myfield: {
value: 'myvalue',
_operation: 'Remove'
}
})
This works well when the array is a string or number. However imagine that I have this document structure, where arrays are actually nested objects:
{
first_name: String,
last_name: String,
subjects: [
{
itemId: String,
title: String,
randomField: String,
dateAdded: Date
}
]
}
In this case the algolia documentation is very unclear. For example, imagine the following scenarios:
I want to update the randomField field of a particular array item. I want to be able to update a nested array item by itemId.
I want to be able to add or remove nested array items. In this case, what do I pass into the "value" field when doing a partialUpdateObject.
Is this kind of thing possible in Algolia? What would be your recommendations?
It's not possible to add/update/remove a specific attribute of a nested array using the partilUpdateObject function.
You get it right by fetching the object, modifying and updating it after. :)
It’s still true that you can’t update individual key value with in a nested object
We're using collection2 (obviously with simple schema) and trying to save an array of objects to a single property on the Meteor.users collection. For example our data might be:
[
{name: "paul"},
{name: "darryn"},
{name: "tom"}
]
in reality our object is more complex
when trying to do this with $set in an update on the users collection we've either gotten 500's or managed to delete the user object entirely when turning off validation.
we've also gotten the following error a number of times:
Validation object must have at least one operator / meteor mongo
This StackOverflow Question mentions it but doesn't offer a solution that makes sense in our context.
My question is two fold. How should the schema be defined for this as we've been trying with type: [Object] which I'm not sure is right, and secondly how should the update statement be created in the method.
Any thoughts, or help would be amazing.
First define the schema for your complex object. Here I've just added age as a key:
Schema.Foo = new SimpleSchema({
name: { type: String },
age: { type: Number, min: 0 }
});
Then augment the user schema with a key whose type is an array of the type you just defined
Schema.User = new SimpleSchema({
foo: { type: [Schema.foo] },
etc...
});