I am using KeystoneJS for Admin DB management. I have a field of type Types.Code in one of my models. I have configured it as below in the model configuration -
Constant.add({
name: { type: String, index: true, required: true, noedit: true },
data: { type: Types.Code, height: 180, language: 'json', noedit: false},
created_at: { type: Date, default: Date.now, noedit: true },
updated_at: { type: Date, default: Date.now, noedit: true }
});
A sample Db entry looks like this:
{
"_id" : ObjectId("5915bd0e995abe638b847897"),
"name" : "constant1",
"data" : {
"value" : 0.5
},
"created_at" : ISODate("2017-04-07T06:39:21.725Z"),
"updated_at" : ISODate("2017-04-07T06:39:21.725Z")
}
But when I visit the page of an entry from this model I see a blank text area.
Apparently, Codemirror is loading fine when I check browser console. The only issue is that the data is not loading in the view. Need help in figuring this out.
Update
I have been able to get the data but it is not parsing as JSON in the UI.
There is a somewhat similar question - Mongoose schema types in KeystoneJS models But it doesn't answer how to show nested objects in KeystoneJS UI.
Keystone Team had replied to a tweet about this https://twitter.com/KeystoneJS/status/453438728485089280
There is an open PR on this issue too - https://github.com/keystonejs/keystone/pull/3282
Related
I am new to cube.js and I am facing a problem, maybe someone will be able to help me. I did not find anything very helpful on the internet...
Here is an example of o document in my collection:
{
"_id" : ObjectId("5a835e0000f73b69c100f15c"),
"studyDescription" : "xxxxxxxx",
"observations" : [
{
"_id" : "1JELIZY6QSAGW",
"state" : "validated",
"stateBy" : "user#xxx.com",
"stateAt" : ISODate("2019-10-22T15:06:48.133+0000"),
"created" : ISODate("2019-10-22T15:06:48.133+0000"),
"createdBy" : "user#xxx.com",
"history" : [
{
"author" : "user#xxx.com",
"role" : "ADMIN",
"state" : "validated",
"tsp" : ISODate("2019-10-22T15:06:48.133+0000")
}
]
}
]
}
My collection contains studies and each study contains several observations. Each observation can be reviewed by one or several reviewers and this information is contained in "history" array. I need to do some reporting so I was advised to use cube.js. Problem is I need to filter some of my charts with data contained in arrays and to do so, i need to do some joins. My problem is that the "observations" array does not contain the study id and the "history" array does not contain either study id nor observations id whereas I would need both to join the tables and filter according to the author for example. I can't join them except if I modify the collection in the database to add the information, which is unfortunately not an option in my case...
Would you have an idea to make this join possible ?
Thank you very much for your help
Embedded documents represented as related tables by Mongo BI connector. In your case there will be following tables:
studies
studies_observations
studies_observations_history
In this case Cube.js schema will look as follows:
cube(`Studies`, {
sql: `select * from studies`,
joins: {
Observations: {
sql: `${Studies}._id = ${Observations}._id`,
relationship: `hasMany`
}
},
measures: {
count: {
type: `count`
}
},
dimensions: {
id: {
sql: `_id`,
type: `string`,
primaryKey: true
}
}
});
cube(`Observations`, {
sql: `select * from studies_observations`,
joins: {
History: {
sql: `${Observations}._id = ${History}._id AND ${Observations}.observations_idx = ${History}.observations_idx`,
relationship: `hasMany`
}
},
dimensions: {
id: {
sql: `CONCAT(${CUBE}._id, ${CUBE}.observations_idx)`,
type: `string`,
primaryKey: true
}
}
});
cube(`History`, {
sql: `select * from studies_observations_history`,
dimensions: {
id: {
sql: `CONCAT(${CUBE}._id, ${CUBE}.observations_idx, ${CUBE}.\`observations.history_idx\`)`,
type: `string`,
primaryKey: true
},
author: {
sql: `${CUBE}.\`observations.history.author\``
}
}
})
Learn more about Mongo BI arrays schema and Cube.js joins.
I am trying to index only the 'particulars' field of boqEntry into an Elasticsearch instance using Mongoosastic and later query them. 'boqList' inside BOQ comprises of boqEntries. I have defined my schema as described in the code below. I am indexing my BOQ document after uploading them via FilePond. Whenever I perform the query (http://localhost:9200/boqss/boqs/_search) onto Elasticsearch.
I get a response like this :
"hits": [
{
"_index": "boqss",
"_type": "boqs",
"_id": "5d9730d83f756d04a8d6dbfe",
"_score": 1.0,
"_source": {
"projectId": "5d860711cf3b052a34a84f6c",
"boqList": [
{
"particulars": "Excavation "
},
{
"particulars": "Providing & laying Rubble Soling"
},
{
"particulars": "Providing & laying PCC M10"
},
{
"particulars": "Providing & Laying Reinforcement With Cutting, Bending & Binding With Binding Wire Etc Complete."
},
{
"particulars": "Providing & Making Double Scaffolding"
},
{
"particulars": "Providing & Casting R.C.C M25"
},
{
"particulars": "Providing & Applying Cement Plaster"
},
...
However I want to be able to retrieve only those specific 'particulars' from the boqList array that match a searchTerm from my search box that I am implementing in my React based front-end, like a full text search. I am relatively new to the MERN stack, Mongoose and Elasticsearch. I would really appreciate any help. Thank you !!
Here is the mongoose schema :
const mongoose = require('mongoose')
const Schema = mongoose.Schema
var mongoosastic = require('mongoosastic')
const boqEntry = new Schema({
particulars : {type : String, es_indexed : true},
quantity : {type : Number},
unit : {type : String},
rate : {type : Number},
amount : {type : Number},
});
const BOQ = new Schema(
{
projectId : { type : String},
boqList : {type : [boqEntry], es_type : 'nested'}
},
{ timestamps: true },
);
BOQ.plugin(mongoosastic)
module.exports = mongoose.model('boqs', BOQ)
I want to find all documents where vendor._id has a certain value. Below is the code, I tried, but it returns nothing.
let name = sampleData.name, _id = sampleData._id
Product.find({"vendor._id":ObjectID(_id)}).then((products) => {
//returns empty array
})
With the same method I tried to query a different field and it works. But I want to query with _id because other fields could vary with time.
Product.find({"vendor.name":name}).then((products) => {
//returns all documents that satisfy the condition.
})
Below is a sample document which I want to find
{
"status" : "active",
"connectedFarms" : [
{
"_id" : "5c412c62bf8a6602f04ae0bf",
"status" : "inActive",
"margin" : 10,
"price" : 55
},
{
"_id" : "5c4567bcb3845b0536a4d92e",
"status" : "inActive",
"margin" : 20,
"price" : 60
},
{
"_id" : "5c4567c4b3845b0536a4d931",
"status" : "active",
"margin" : 7,
"price" : 53.5
}
],
"vendor" : {
"_id" : ObjectId("5c3fcc0c7657ee02ac24bc21"),
"name" : "manna"
}
}
And here is the schema for this document.
let ProductSchema = new mongoose.Schema({
vendor:{_id:String, name:String},
connectedFarms:[{_id:String, name:String, status:String, price:Number, margin:Number}],
status:{
type:String,
trim: true,
minlength:1
}
});
Let's take a different approach on this, and make vendor its own schema. Mongoose does not allow you to nest schemas, so you cannot make the vendor._id a true ObjectID.
Vendor Schema
const VendorSchema = new mongoose.Schema({
name: string
});
module.exports = mongoose.model('Vendor', VendorSchema);
Product Schema
const ProductSchema = new mongoose.Schema({
vendor: {
type: mongoose.Types.ObjectID,
ref: 'Vendor'
},
connectedFarms: [{
_id: String,
name: String,
status: String,
price: Number,
margin: Number
}],
status: {
type: String,
trim: true,
minlength: 1
}
});
module.exports = mongoose.model('Product', ProductSchema);
Now when you want to query a product based on the vendors _id, it's very simple! All you need to do is supply the _id of the vendor in the query. NOTE: There is no reason to convert the _id to an ObjectID in the query, as mongoose accepts strings and converts them later on.
Query
const vendorID = myVendor._id;
Product.find({ vendor: vendorID })
.then((products) => {
// Do something with the found products
});
That's it! Much simpler to do, and much cleaner in the database. The vendor field is now easier to reference. You also have the ability to get the full vendor object in a query if desired by populating in the query. The difference is, the population will return the vendor name and _id, rather than just the _id. To do this, run the following:
Product.find({ vendor: vendorID })
.populate('vendor')
.then((products) => {
// Do something with the populated found products
});
Create Collection with validator
db.createCollection("claims",
{ validator : { $jsonSchema : { bsonType : "object",
properties : { airportCode : { bsonType: "string"} },
additionalProperties: false}
} } )
Insert
db.claims.insert({"airportCode" : "DSM"}) => result: "errmsg" : "Document failed validation"
if I remove "additionalProperties: false" by creating the collection, when I can insert the document.
Any advice, how to keep "additionalProperties: false", because I want to control the document.
As at MongoDB 3.6.2, JSON Schema validation does not automatically add the default _id property, so you need to include a rule for this when using additionalProperties: false.
For example, assuming the default ObjectID:
db.createCollection("claims",
{ validator : {
$jsonSchema : {
bsonType : "object",
properties : {
_id: { bsonType: "objectId" },
airportCode : { bsonType: "string"}
},
additionalProperties: false
}
}}
)
Two related issues to upvote/watch on the MongoDB Jira issue tracker:
SERVER-32160: provide warning when _id is not in list of properties and additionalProperties is false
SERVER-20547: Expose the reason an operation fails document validation
After my initial question:
Handling relationships in Mongo and Sails?
I managed to use this approach, however I now need to resolve this the way I originally thought. For example, I have my Photo and Category models & collections, but now my category also contains addresses and business details.
In my Photo model I have the following:
attributes: {
caption : { type : 'string' },
fid : { type : 'string' },
user : { model : 'user' },
categories : { model : 'category', type : 'array'}
}
In my Category model I have the following:
attributes: {
photo : { model: 'photo' },
category : { type: 'string'},
address : { type: 'string'},
phone : { type: 'integer'},
//Foreign Keys
categories : { collection: 'photo', via: 'categories', type : 'integer'}
}
Now I can get the categories in the Photo collection to show as an ObjectID if I removed the type array and just send a single ObjectID of a category, however in my case, a photo can have more than one Category.
If I try sending an array of ObjectID's in my query, they just show up in the database as a String array. Is there anyway I get store these as an array of ObjectID's instead?
Basically it's many to many relationship. You can use Waterline scheme like this:
Photo Model
attributes: {
caption : { type : 'string' },
fid : { type : 'string' },
user : { model : 'user' },
categories : { collection : 'category', via : 'photos'}
}
Category Model
attributes: {
photos : { collection: 'photo', via: 'categories' },
category : { type: 'string'},
address : { type: 'string'},
phone : { type: 'integer'},
}