Not understanding mongoose schema array syntax - javascript

I'm having trouble wrapping my head around the below syntax in a mongoose schema.
tokens:[{
token:{
type: 'String',
required: true
}
}]
Normally when I want to add objects to arrays I would just push the object. That includes if I want to push an object with an internal object to said array like the example below.
let obj =[]
obj.push({name: 'dirk', age: 24})
obj.push({name: 'chris', age:29, clothes: {shirt: 'black', pants: 'jeans'}, height: '6ft'})
So im confused in mongoose as to why I need this syntax [{}] to use an array?

Ok I'll try to explain this as best I can. In basic JavaScript, an array is just a bucket of "stuff" for lack of better words. What that means is, you could have something like this:
let myList = []
myList.push({name: "John Doe", age: 20})
myList.push({car: {make: "Honda", model: "Accord"}})
myList.push({menu_items: ["item 1", "item 2", "item 3"]})
And JavaScript won't really care right? As far as it's concerned, you haven't done anything wrong because you technically did the correct thing, put some object into a list that can hold whatever you want.
Mongoose, which is an ORM (check out the term if you haven't heard of it before), requires things be a little more strict. Remember that Mongoose is trying to map documents from the Mongo database to this "Object" that should be standard and readable from any point in the code the same what. So in the example in your question listed above:
tokens:[{
token:{
type: 'String',
required: true
}
}]
you are saying to Mongoose that it should expect tokens to contain a list of token objects that have a certain design to them. Now, when you want to add more token objects to the tokens list, you can do something like this:
token = {
// YOUR CORRECT TOKEN DATA
}
tokens.push(token);
If you tried to do something like this instead:
token = {
// RANDOM WRONG DATA
}
tokens.push(token);
Mongoose wouldn't take kindly to it because you are violating the constraints you told Mongoose to keep in affect. If you start throwing any: [{}] into the mix, you are telling Mongoose that any old object will do for that list. This is, in my opinion, very dangerous to do because if you have two types of objects in your list:
var schema1 = new Schema({
name: String,
age: { type: Number, min: 18, max: 65 },
living: Boolean
})
var schema2 = new Schema({
name: String,
age: { type: Number, min: 18, max: 65 },
breed: Boolean
})
and you were working with a list that combined these two objects, if you tried to grab say breed from the schema1 type object, you would either get an error or an odd value that could break your code. So Mongoose strictly types the objects you are pushing to a list, unless you use something like Mixed or any. Here's a link to the documentation that may help explain a bit as well
https://mongoosejs.com/docs/schematypes.html#arrays
If this doesn't make sense or I explained it poorly or answered the wrong question please comment and I'll fix it to explain as best I can.
Happy coding :-)

Related

MongoDB return embedded document in array of arrays

I am learning the MongoDB aggregation framework and I'm struggling with this particular query to return subdocuments as arrays within an array;
My schema is something like this
board: {
_id: ObjectId,
name: 'general',
prefix: 'gen',
threads: [ObjectId, ObjectId, ObjectId]
}
thread: {
_id: ObjectId,
title: 'some title',
body: 'some content',
creator: {
_ref: ObjectId
},
board: {
_ref: ObjectId,
name: 'general',
prefix: 'gen'
},
createdAt: 'time string',
updatedAt: 'time string',
posts: [ObjectId, ObjectId, ObjectId]
}
post: {
_id: ObjectId,
thread: ObjectId,
body: 'some post content',
createdAt: 'time string',
updatedAt: 'time string',
creator: {
_ref: ObjectId
}
}
(don't worry about how it looks. it's designed very specifically and I left out a lot of unnecessary fields and also included some to give a more simplified overview)
Each board can have many many different threads. I am trying to create sort of a customized pagination. I want to return the boards object, where the threads field is an array of threads of a maximum size. so for example if I had 108 threads in this board, it would return 11 arrays inside threads. the first 10 have 10 threads each, the last has 8. I also want the threads inside each array to be populated with their corresponding document. That's not the issue for me. it's creating the actual arrays.
note: the threads field is NOT an unbounded array. it has a maximum size that is unknown at the moment.
I CANNOT use the ObjectId to create the arrays. I have read solutions which take advantage of the fact that ObjectId includes creation data and more, and it was a good solution, however - I cannot use it for my implementation. I have many different types of sorting options and the createdAt and updatedAt fields are manipulated sparsely to aid in some additional sorting after the fact.. anyway this is no concern, I simply wanted to state that I am aware of this solution, but I cannot use it.
I have tried so many different solutions, none of which worked. I would really like to do this during the query and not in javascript if possible. If it's not possible inside the query, what would be the best solution to achieve the desired result in javascript? I am using a nested loop at the moment and I would really like to avoid this but I am unsure of how to.

How to optimize performance of searching in two array of object

There are two array of objects one from database and one from csv. I required to compare both array object by their relative properties of Phones and emails and find duplicate array among them. Due to odd database object structure I required to compare both array with Javascript. I wanted to know what is the best algorithm and best way of compare and find duplicates?
I explain simple calculations.
There are 5000 contacts in my database and user may upload another 3000 contacts from csv. Everytime we requires to find duplicate contacts from database and if they find then it may overwrite and rest should be insert. If I compare contact row by row then it may loop 5000 database contacts x 3000 csv contacts = 15000000 time traverse.
This is my present scenario I face due to this system goes stuck. I require some efficient solution of this issue.
I develop the stuff in NodeJS, RethinkDB.
Database object structure exactly represent like that way and it may duplicate entry of emails and phones in other contacts also.
[{
id: 2349287349082734,
name: "ABC",
phones: [
{
id: 2234234,
flag: true,
value: 982389679823
},
{
id: 65234234,
flag: false,
value: 2979023423
}
],
emails: [
{
id: 22346234,
flag: true,
value: "test#domain.com"
},
{
id: 609834234,
flag: false,
value: "test2#domain.com"
}
]
}]
Please review fiddle code, if you want: https://jsfiddle.net/dipakchavda2912/eua1truj/
I have already did indexing. The problem is looking very easy and known in first sight but when we talk about concurrency it is really very critical and CPU intensive.
If understand the question you can use the lodash method differenceWith
let csvContacts = [] //fill it with your values;
let databaseContacts = .... //from your database
let diffArray = [] //the non duplicated object;
const l = require("lodash");
diffArray = l.differenceWith(csvContact,
databaseContacts,
(firstValue,secValue)=>firstValue.email == secValue.email

Assign key and variable without need to assign in Schema

I have the following mongodb / mongoose Schema
var forumReplySchema = new Schema({
userid : String,
username: String,
forumid: {type: String, default: '1'},
message: {type: String, default: ''},
time: Number,
});
module.exports = mongoose.model('forum_replies', forumReplySchema);
with following query:
forum_replies.findOne({forumid: forumid}).then(function (reply) {
currentReply.username = user.username;
currentReply.rank = result.rank;
});
Currently username is assigned cause i have username property in the Schema.
Rank is not assigned cause its not in the Schema.
But is there a way for me to assign rank, without having it defined in the Schema?
Edit: aka, assign rank to the forum replies object without the need to save in Db.
you cannot add properties to mongoose document. If you want to do so, you will need to convert it into plain object first. There are couple of ways you could go about it. Following is one of them.
reply.toObject();
Then you can add properties to it.
//you have currentReply in your code, I just want to show general idea here
reply.rank = result.rank;
Is this what you are looking for?
Update:
Thanks for accepting answer :). Also look into lean() option, this returns you plain JS objects without you having to do the conversion manually. lean() also has performance benefit.

JavaScript array of objects conversion

I wasnt exactly sure what i should name this question so feel free to edit the title.
I am running an angular application and using node.js combinded with express and sequlize (for my ORM)
Now as many of you may know when your working with an ORM you want to collect Objects inside of another Object for instance a user object might have a country object inside of it as shown below:
user = {id: 222, username: 'Marc', name: 'Marc Ras', country: {id: 1, code: 'DK', name: 'Denmark'}}
Now this is great. binding all of these objects together makes it alot easier to work with in the frontend.
However the other way around is rather annoying.
Lets for the purpose of demonstration take the above object. but lets add a property an array of items
user.items = [{id: 1 , name:'item1'}, {id: 2, name: 'item2'}]
Now if i wish to add this object to my database i would send the combined object to my express route:
var user = {
id: 222,
username: 'Marc',
name: 'Marc Ras',
country: {id: 1, code:'DK', name: 'Denmark'}
items: [
{id: 1, name: 'item1'},
{id: 2, name: 'item2'}
]
}
And now things get abit messy
Say for instance you have the following table:
user_has_items
Each record in this has an id, user_id, item_id
Now in order to make sure that the objects inside user.items match the table you will now have to make code gymnastic by making loops and editing the above object.
Like as such:
user.items.forEach(function (x) {
x.item_id = x.id;
x.id = null; // To make sure the database does not set the id (since this is auto inc)
x.user_id = user.id;
})
Note the above is of course an example it gets more complicated the bigger your object is!
This process leads to messy code (atleast in my opinion) and since this is not the first time i encounter this problem i was wondering if any of you had any solutions as to what you might do to make this process easier?
I have been looking at lodash to see if they had some way of doing this but sadly i could not find anything that made this easy

JavaScript multidimensional get value without looping

I've got a question,
I've got an array in Javascript that looks like this:
var plans = [{
'advanced':[{
'price':'10',
'name':'Advanced'
}],
'basic':[{
'price':'20',
'name':'Basic'
}]
}];
And there's a variable called plan, this could be advanced or basic etc. Now I want to display the price from the array that corresponds with the variable plan. How do I get the price?
I've tried things like:
plans.advanced.price
plans['advanced']['price']
plans[0].advanced['0'].price
plans[0]['advanced']['0']['price']
PS: I am originally A PHP developer, maybe my PHP influence is blocking the correct thoughts, i dont know...
Access it like this: plans[0].advanced[0].price
That's the wrong way to be going about it though; just use JavaScript objects:
var plans = {
advanced: {
price: '10',
name: 'Advanced'
},
basic: {
price: '20',
name:' Basic'
}
};
Then you can access it using plans.advanced.price, which is much more clear.
Note that plans.advanced.price is the same as plans['advanced']['price'] in JavaScript, there is no difference.
Arrays in JavaScript are just glorified objects - as such there is no such thing as "associative arrays" in JavaScript, objects perform the same thing as associative arrays in PHP.
you have some extra array cruft, where you have arrays with one item in them instead of just having the object.
var plans = {
advanced: {
price: '10',
name: 'Advanced'
},
basic: {
price: '20',
name:' Basic'
}
};
if you have var plan ="advanced" you can just do plans[plan].price
if you NEED the current structure with the arrays then it is essentially the same thing but
var plan ="advanced"
plans[0][plan][0].price
hope that helps

Categories