Mongoose validating embedded - mongodb

I created the following schema (coffeescript):
user_schema = new app.db.schema(
username: String
email: String
password: String
account:
plan:
type: String
default: "Free"
enum: ["Free", "Bronze", "Silver", "Gold"]
comments: [
title: String
message: String
date_added: Date
]
)
I could have probably created 2 more schemas here (account and comment) but I know each user has one account associated and each account has maximum 100 comments so I like the idea of having it all inside a single document. It's not making sense I know (user/account/comments) but I'm just familiarizing myself to noSql and rich documents so it's just a test.
My question is about saving a new comment for a given account and validating them. I can validate a user email by doing this (which works btw):
user_schema.path("email").validate((value, respond)->
respond v.check(value).isEmail()
, "Invalid email address")
...but how would I validate a comment? How do I save a new comment under a given user.account.comments array? Comments are not required by default but if a new comment is added I want to validate that the title and message is required let's say.
Is this type of nesting normal or I have to create separate models and reference them? I read a lot about embedding vs linking and I feel like this would make for an embed?

You put the validation attributes right in the schema definition of the embedded object:
comments: [
title:
type: String
required: true
message:
type: String
required: true
date_added: Date
]

Related

Best practices with connecting data from 2 models

I've got two models: Note and Profile. Note contains foreign key of connected profile as you can see below.
Note: {
profile_id: String,
date: String,
content: String,
}
Profile: {
id: String,
name: String,
profilePicture: String
}
I want to get all notes and also name and profile picture of note.
In this situation should I:
get all notes and all profiles and then join them locally in for loop,
get all notes and then in for loop ask DB for name and picture of matching profile,
other option
Which way is recomended?
Take a look at mongoose's Populate. You can declare a Schema property with type: Schema.Types.ObjectId, ref: 'Profile'. When you run a Query you can .populate() this field with the corresponding document.

Proper way to implement a User record with id vs _id

I am having trouble understanding the proper way to implement a MongoDB User record type, to use with GraphQL. Specifically, it has to do with the user id.
I would like to be able to query for a user record and get a user id as 'id'. MongoDB records have a _id by default.
How do I accomplish this?
do I have to define the user record as:
type User {
id: ID!
name: String!
email: String!
}
Should I then populate the 'id' field on my own when creating a record?
Or should I just use the _id as a user id? if so, how do I query it? I get issues saying that I cannot query it. I think because it's not in the typedef.
I'm using TypeGraphQL along with TypeORM, and there you can create mapping by using decorators:
#Field(type => ID!, { name: 'id' })
#Column({ type: '_id', nullable: false, unique: true })
public _id: string;

Canvas PowerApp Form unable to get fields from Custom Connector returning tabular data from REST API

I created a Custom Connector our of my REST API that returns tabular data. I used it as a datasource in a canvas powerapp, which store the records from the custom connector into a collection. This collection is used as datasource by a Gallery which successfully displays the items and attributes of each item. However, when I try to create an Edit Form that uses the collection as datasource it cannot access the fields. It does not work using directly the custom connector as data source either.
In this answer from #aorphan I read that you can use custom connectors in forms as long as they return tables instead of actions. And as far as I can see, the content of the collection is tabular data:
Even the columns of the collection can be accessed as attributes of the item displayed by the Gallery:
However, even after setting the collection as datasource of a new Edit Form, it is unable to add any fields from the datasource:
Just in case my data needs some richer definition to be correctly interpreted by the Form, the JSON returned by my API looks like this:
{
"quotes": [
{
"quote_pk": 347,
"shipment_name": "test add leg",
"organization_ff_name": "LIFE",
"quote_id": "1234",
"effective_until": "2020-05-10",
"eta": "2020-05-14T12:00:00Z",
"price": 100.0,
"quote_status": 2
},
{
"quote_pk": 345,
"shipment_name": "test modal review",
"organization_ff_name": "LIFE",
"quote_id": "123",
"effective_until": "2020-05-11",
"eta": "2020-05-22T12:00:00Z",
"price": 1749.94,
"quote_status": 6
}
]
}
And the definition of my Custom Connector goes like this:
swagger: '2.0'
info: {title: some title, description: some description, version: '1.0'}
host: server.domain.com
basePath: /organizations/endpoint/
schemes: [https]
consumes: []
produces: []
paths:
/organizations/endpoint/shipment_quotes/: {}
/shipment_quotes/:
get:
responses:
'200':
description: default
schema:
type: object
properties:
quotes:
type: array
items:
type: object
properties:
quote_pk: {type: integer, format: int32, description: quote_pk}
shipment_name: {type: string, description: shipment_name}
organization_ff_name: {type: string, description: organization_ff_name}
quote_id: {type: string, description: quote_id}
effective_until: {type: string, description: effective_until}
eta: {type: string, description: eta}
price: {type: number, format: float, description: price}
quote_status: {type: integer, format: int32, description: quote_status}
description: quotes
summary: peration summary
description: operation description
operationId: operationId
parameters:
- {name: Content-Type, in: header, required: false, type: string}
- {name: Accept, in: header, required: false, type: string}
definitions: {}
parameters: {}
responses: {}
securityDefinitions: {}
security: []
tags: []
Please help me to get the datasource right so the form be able to add its fields, or at least let me know in case this is not possible for some reason so I can move on.
Formally, Collections cannot be used as a DataSource for Form controls in PowerApps. You're efforts are admirable and it looks like you've tried just about everything, so I'll pass my little secret.
Its probably not officially supported so use at your own risk.
Create a Collection of the response from your Custom Connector (which you've done)
Add a Gallery control and set its Items property to the Collection (which you've already done)
Add an Edit Form control and set its DataSource property to the Collection (which you've already done)
Click the three little dots and Add Custom Card
Add a TextBox control to the Custom Card.
Set the TextBox Default property to gallery.Selected.X where "X" is the value you want to edit in the form.
Repeat steps 4-7 for each form field you wish to capture.
Create a "Submit" button in the Form which Patches/UpdateIf's the Collection then calls your POST (or PUT) method from the Custom Connector to patch the edits back to your DataSource.
8a. I only see a GET request in your swagger file. You'll (obviously) need a POST/PUT to get the data from the Collection back up to your DataSource.
8b. This little "wrapper" is likely what PowerApps handles for you when you use an "approved" DataSource for a Form control.
Note: Your Form will show "No data source" in the PowerApps studio, but your user won't see it.
Here it is in action:
Help much?

Database design - saving the entire object to a user or just the id of an object?

database noob here using MongoDB, in my program, I have users, and the core of my program are these roadmaps that I display. So, each user can create roadmaps, save others roadmaps, blah blah... Each user has a field named savedRoadmaps and createdRoadmaps which should store the roadmaps. My question is, should I just store the roadmap _ids in the savedRoadmap and createdRoadmaps field or the entire roadmap?
I am asking this because it feels like saving just the _id of the roadmaps can save storage, but it might not come in handy when I have to fetch the data of the user first, then fetch the roadmap using the roadmap ID in the user's savedRoadmap/createdRoadmap field, versus just fetching the user and the savedRoadmap field will already have the roadmap in there.
And btw, is there any sweet and brief database design read out there, please direct me to some if you know any!
For a user, I want it to have a name, email, password, description ofcourse, and also savedRoadmaps and createdRoadmaps. A user can create unlimited roadmaps and also save as much as he or she wants. For a roadmap, I want it to have a name, category, time_completion, author, date, and a roadmap object which will contain the actual json string that I will use d3 to display. Here's my User and Roadmap Schema right now:
const RoadmapSchema = new Schema({
author: {
type: String,
require: false
},
name: {
type: String,
require: true
},
category: {
type: String,
require: true
},
time_completion: {
type: Number,
require: true
},
date: {
type: Date,
default: Date.now
},
roadmap: {
type: "object",
require: true
}
});
and User Schema:
const UserSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
savedRoadmap: {
type: "object",
default: []
},
createdRoadmap: {
type: "object",
default: []
}
});
My question is, inside of the savedRoadmap and createdRoadmap fields of the User schema, should I include just the _id of a roadmap, or should I include the entire json string which represents the roadmap?
There are 3 different data-modeling techniques you can use to design your roadmaps system based on the cardinality of the relationship between users and roadmaps.
In general you need to de-normalize your data model based on the queries that are expected from your application:
One to Few: Embed the N side if the cardinality is one-to-few and there is no need to access the embedded object outside the context of the parent object
One to Many: Use an array of references to the N-side objects if the cardinality is one-to-many or if the N-side objects should stand alone for any reasons
One-to-Squillions: Use a reference to the One-side in the N-side objects if the cardinality is one-to-squillions
And btw, is there any sweet and brief database design read out there,
please direct me to some if you know any!
Rules of Thumb for MongoDB Schema Design: Part 1

Node.js - Mongoose/MongoDB - Model Schema

I am creating a blog system in Node.js with mongodb as the db.
I have contents like this: (blog articles):
// COMMENTS SCHEMA:
// ---------------------------------------
var Comments = new Schema({
author: {
type: String
},
content: {
type: String
},
date_entered: {
type: Date,
default: Date.now
}
});
exports.Comments = mongoose.model('Comments',Comments);
var Tags = new Schema({
name: {
type: String
}
});
exports.Tags = mongoose.model('Tags',Tags);
// CONTENT SCHEMA:
// ---------------------------------------
exports.Contents = mongoose.model('Contents', new Schema({
title: {
type: String
},
author: {
type: String
},
permalink: {
type: String,
unique: true,
sparse: true
},
catagory: {
type: String,
default: ''
},
content: {
type: String
},
date_entered: {
type: Date,
default: Date.now
},
status: {
type: Number
},
comments: [Comments],
tags: [Tags]
}));
I am a little new to this type of database, im used to MySQL on a LAMP stack.
Basically my question is as follows:
whats the best way to associate the Contents author to a User in the
DB?
Also, whats the best way to do the tags and categories?
In MYSQL we would have a tags table and a categories table and relate by keys, I am not sure the best and most optimal way of doing it in Mongo.
THANK YOU FOR YOUR TIME!!
Couple of ideas for Mongo:
The best way to associate a user is e-mail address - as an attribute of the content/comment document - e-mail is usually a reliable unique key. MongoDB doesn't have foreign keys or associated constraints. But that is fine.
If you have a registration policy, add user name, e-mail address and other details to the users collection. Then de-normalize the content document with the user name and e-mail. If, for any reason, the user changes the name, you will have to update all the associated contents/comments. But so long as the e-mail address is there in the documents, this should be easy.
Tags and categories are best modelled as two lists in the content document, IMHO.
You can also create two indices on these attributes, if required. Depends on the access patterns and the UI features you want to provide
You can also add a document which keeps a tag list and a categories list in the contents collection and use $addToSet to add new tags and categories to this document. Then, you can show a combo box with the current tags as a starting point.
As a final point, think through the ways you plan to access the data and then design documents, collections & indices accordingly
[Update 12/9/11] Was at MongoSv and Eliot (CTO 10gen) presented a pattern relevant to this question: Instead of one comment document per user (which could grow large) have a comment document per day for a use with _id = -YYYYMMDD or even one per month depending on the frequency of comments. This optimizes index creation/document growth vs document proliferation (in case of the design where there is one comment per user).
The best way to associate the Content Authors to a User in the MongoDB, is to take an array in Author Collection which keeps an reference to User. Basically Array because One Content/Book may have multiple Authors i.e. you need to associate one Content to many Users.
The best way for category is to create a different collection in your DB and similarly as above keep a array in Contents.
I hope it helps at-least a little.