For this project, I'm building out models and passing in values from the body of a POST request. I want to understand how I should be declaring the models.
Sample of JSON which I want to be posted to MongoDB.
{
"signageId": "5cd857c4965f863b7c88d24a",
"parameters": {
"imageURL": "url.com",
"page": {
"pageHeight": "100", //want to change to "height"
"pageWidth": "100" //want to change to "width"
},
"density": {
"height": "300",
"width": "300"
}
}
}
I want to name pageHeight and pageWidth just "height" and "width" within the JSON, like I have done for the density segment, but I'm having difficulties knowing how to declare the models and grab the values from the request.
Model I'm using:
const ObjectSchema = new Schema({
signageId: {
type: String,
require: true
}
parameters: {
imageURL: {
type: String,
require: true
}
},
page: {
pageHeight: {
type: String
},
pageWidth: {
type: String
}
},
density: {
height: {
type: String
},
width: {
type: String
}
}
}
});
Post router
router.post('/', (req, res) =>{
const object = new Objects({
signageId: req.body.signageId,
imageURL: req.body.imageURL,
page: req.body.page,
pageHeight: req.body.pageHeight,
pageWidth: req.body.pageWidth,
density: req.body.density,
height: req.body.height,
width: req.body.width
});
try {
object.save();
res.json({object});
}
catch (err) {
res.json({message: err});
}
});
Your new object should be something like this.
const newObject = new Objects({
signageId: req.body.signageId,
parameters: {
imageURL: req.body.imageURL,
page: {
height: req.body.pageHeight,
width: req.body.pageWidth,
},
density: {
height: req.body.height,
width: req.body.width,
}
}
});
Notes:
1. Give your mongoose schema another name, in order to avoid javascript conflicts.
2. You can use height and width properties for different objects.
page: {
height: {
type: String
},
width: {
type: String
}
},
density: {
height: {
type: String
},
width: {
type: String
}
}
3. the model properties should be required, not require
Related
I am trying to return a mongodb document upon a graphql query but getting null value. No error is being shown. The mongodb query works fine with mongoshell or mongoose.
Here is the schema, typedef and resolver:
const unionSchema = new Schema(
{
geometry: mongoose.Schema.Types.MultiPolygon,
properties: {
Divi_name: String,
Dist_name: String,
Upaz_name: String,
Uni_namae: String,
},
},
{ collection: "unionbounds" }
);
const union = mongoose.model("Union", unionSchema);
const typeDefs = `
type Query {
data: Union
}
type Union {
properties: Props
}
type Props{
Dist_name: String,
}
`;
const resolvers = {
Query: {
data: () => {
union.findOne(
{
geometry: {
$geoIntersects: {
$geometry: {
type: "Point",
coordinates: [90, 22],
},
},
},
},
"properties"
);
},
},
};
Mongoshell query returns the document:
{
properties: {
Div_ID: '10',
Dist_ID: '04',
Upz_ID: '28',
Un_ID: '95',
Un_UID: '10042895',
Divi_name: 'Barisal',
Dist_name: 'Barguna',
Upaz_name: 'Barguna Sadar Upazila',
Uni_name: 'Naltona',
Area_SqKm: 45.7658667915
},
_id: 6001e54a51c6d49215322f94
}
My suspicion is that I am doing something wrong in the resolver function. I would appreciate any suggestion.
The problem was indeed the resolver function. Following code worked after returning the result from the callback function and using async .. await.
const resolvers = {
Query: {
data: async () => {
var value;
await union.findOne(
{
geometry: {
$geoIntersects: {
$geometry: {
type: "Point",
coordinates: [90, 22],
},
},
},
},
"properties",
function (err, result) {
value = result;
}
);
return value;
},
},
};
When I am doing custom mapping using kibana its working properly but when I am doing the same thing in my node program its showing mapper parsing exception.
Reason:Root mapping definition has unsupported parameters:tags(custom mapping name)
Because in kibana i am able to use include_type_name =true but in my node program it is not available.
var name = req.body.templatename;
var index_patterns = req.body.index_patterns;
console.log(index_patterns);
const opts: IndicesPutTemplateParams = {
name: name,
body: {
index_patterns: [index_patterns],
settings: {
analysis: {
filter: {
autocomplete_filter: {
type: "edge_ngram",
min_gram: 1,
max_gram: 20
}
},
analyzer: {
autocomplete: {
type: "custom",
tokenizer: "standard",
filter: [
"lowercase",
"autocomplete_filter"
]
}
}
}
},
mappings: {
tags: {
properties: {
name: {
type: "text",
analyzer: "autocomplete",
search_analyzer: "standard"
},
normalized: {
type: "text"
},
status: {
type: "text"
},
createdat: {
type: "date"
},
updatedat: {
type: "date"
}
}
}
}
}
}
try {
esClient.indices.putTemplate(opts).then((data: any) => {
return res.json({
data
});
console.log(data);
}).catch((err: any) => {
console.log(err);
res.status(500).json({
err
})
});
} catch (error) {
res.status(500).json({
error
})
}
}```
As Per documentation you need to give include_type_name as
client.indices.putTemplate({
name: string,
include_type_name: boolean, --->
order: number,
create: boolean,
timeout: string,
master_timeout: string,
flat_settings: boolean,
body: object -> mapping object
})
Or you can drop mapping name tags from mapping
mappings: {
tags: { ---> remove
When saving an entity with mongoose and graphql the following happens:
First method to save:
create(budgetProps){
const budget = new Budget(budgetProps);
return budget.save();
}
The result is as follows:
{
"data": {
"addBudget": {
"_id": "59fbdefaa7b0a81180dd2c9c",
"tiempoAproximado": 2245.5,
"User": {
"name": null,
"organization": null
},
"Vehicle": {
"name": null,
"type": null
}
}
}
}
Using this method:
create(budgetProps){
const budget = new Budget(budgetProps);
return budget.save().then((res)=>{
Budget.findById(res._id)
.populate('User')
.populate('Vehicle')
.exec((err, newBudget)=> {
return newBudget;
});
});
},
I get the following:
{
"data": {
"addBudget": null
}
}
This is the Schema:
const typeDefs = `
scalar Date
input UserInput {
_id: ID,
name: String,
organization: String,
phones: [String],
emails: [String],
type: String,
password: String,
percentaje: String
}
input VehicleDescriptionInput {
es: String,
en: String
}
input VehicleInput{
_id: ID,
name: String,
passengers: Int,
largeBags: Int,
smallBags: Int,
doors: Int,
type: String,
status: Boolean,
imagesUrls: [String],
description: VehicleDescriptionInput
}
input FinalTotalCostInput {
es: String,
en: String
}
input BudgetTotalCostInput {
es: String,
en: String
}
input BudgetInput {
finalTotalCost: FinalTotalCostInput,
budgetTotalCost: BudgetTotalCostInput,
destinoInicial: String,
destinoFinal: String,
tiempoAproximado: Float,
distancia: Float,
tollCost: Float,
tolls: [String],
budgetDate: Date,
aprove: Boolean,
User: UserInput,
Vehicle: VehicleInput
}
type Mutation {
addBudget(data: BudgetInput): Budget
}
`;
Here is the resolver:
Mutation: {
addBudget: (_, {data}) =>{
return BudgetController.create(data);
}
},
Finally here is the mutation with its variables:
mutation addBudget($budget: BudgetInput) {
addBudget(data: $budget) {
_id
User{
name
organization
}
Vehicle{
name
type
}
}
}
{
"budget": {
"finalTotalCost": {
"es": "100 peso",
"en": "10 dolars"
},
"budgetTotalCost": {
"es": "80 peso",
"en": "8 dolars"
},
"destinoInicial": "Queretaro",
"destinoFinal": "Sonora",
"tiempoAproximado": 2245.5,
"distancia": 100.565,
"tollCost": 20.5,
"tolls": [
"GDL",
"Marina",
"Culap",
"MalageƱa"
],
"budgetDate": "2017/07/21",
"aprove": false,
"User": {
"_id": "59fbcc42aa82460924e5fbad"
},
"Vehicle": {
"_id": "59fbcbe4aa82460924e5fbac"
}
}
}
The entity is stored properly in the database, when Console.log the result of the populated search results are correct then I do not understand what is happening.
You can find the whole app in the following link: GitHub Repo
You're mixing Promises and callbacks. exec() will return a Promise, but only if doesn't have any arguments passed to it. Additionally, you need to return the Promise that's returned by exec().
return budget.save().then((res) => {
return Budget.findById(res._id) // missing return here
.populate('User')
.populate('Vehicle')
.exec() // don't need anything else
})
You can clean this up a little more:
return budget.save()
.then(res => Budget.findById(res._id)
.populate('User')
.populate('Vehicle')
.exec())
If you need to transform the results returned by findById before turning them over to the client:
return budget.save()
.then(res => Budget.findById(res._id)
.populate('User')
.populate('Vehicle')
.exec())
.then(res => {
res.foo = 'Foo'
return res
})
I have one document like that
var ConfigSchema = new Schema({
basicConfig: {
levelId: {
type: Number,
required: true
},
hostId: {
type: Number,
required: true
},
Name: {
type: String,
trim: true
},
Settings: {
Type1: {
// some types here...
}
Type2: {
// some types here...
}
}
},
enrolls: {
name: {type: String},
list: [String]
},
awards: {
enable: {type: Boolean},
Primary: {
amount: {type: Number},
type: {type: String}
}
}
Now I want to find configs with hostId matches 60, and selecting basicConfig field.
Config.findOne({ 'basicConfig.hostId': 60 })
.select('basicConfig').exec(function(err, configs) {
if (err) {
console.error(err);
return ;
}
console.log(configs);
});
However, all fields of this document will be returned. It seems that the select does NOT work? Why?
Output:
{ _id: 555c4144c0bff1541d0e4059,
enrolls: {},
awards: { primary: { PrimarySettings: {}, primaryAck: {} } },
basicConfig:
{ levelId: 24,
hostId: 60,
poolName: 'LC' } }
Also, those following codes have been test, it does not work.
BonusConfig.findOne({ 'basicConfig.hostId': 60 }, 'basicConfig', function(err, configs) {
if (err) {
console.error(err);
return ;
}
console.log(configs);
});
But, without the basicConfig field with select with the following codes, it work well.
BonusConfig.findOne({ 'basicConfig.hostId': 60 })
.select('-basicConfig').exec(function(err, configs) {
if (err) {
console.error(err);
return ;
}
console.log(configs);
});
What's wrong with my codes?
Mongoose version: 3.8.24
Mongodb version: 2.6.7
Edit 1
Here is the query log in mongoose debug mode.
Mongoose: configs.findOne({ 'basicConfig.hostId': 60 }) { fields: { basicConfig: 1 } }
Edit 2
After further investigation.
The output result of Config.findOne({ 'basicConfig.hostId': 60 }).select('basicConfig'):
{ _id: 555c4144c0bff1541d0e4059,
enrolls: {},
awards: { primary: { PrimarySettings: {}, primaryAck: {} } },
basicConfig:
{ levelId: 24,
hostId: 60,
poolName: 'LC' } }
Other fields are empty value except basicConfig. However, I want the result is
{ _id: 555c4144c0bff1541d0e4059,
basicConfig:
{ levelId: 24,
hostId: 60,
poolName: 'LC' } }
Your projection of fields that need to be returned is missing the additional parameter. Try this:
BonusConfig.findOne({ 'basicConfig.hostId': 60 }, {'basicConfig':1}, function(err, configs) {
if (err) {
console.error(err);
return ;
}
console.log(configs);
});
Quoting this
This behavior is by design, but admittedly it's not very well-designed. Mongoose is over-eager when it comes to creating sub-docs when loading from the database. Planning on changing that in v5.
I want to display predictive text in search field, value for predictive text which comes from server. Here is my code so far:
View:
Ext.define('MyApp.view.AutoSearch', {
extend: 'Ext.dataview.List',
alias : 'widget.mainPanel',
config: {
store : 'AutoSearchStore',
itemTpl: '<div class="myWord">'+
'<div>Word is --<b>{name}</b>--- after search!!!</div>' +
'</div>',
emptyText: '<div class="myWord">No Matching Words</div>',
items: [
{
xtype: 'toolbar',
docked: 'top',
items: [
{
xtype: 'searchfield',
placeHolder: 'Search...',
itemId: 'searchBox'
}
]
}
]
}
});
Store:
Ext.define('MyApp.store.AutoSearchStore',{
extend: 'Ext.data.Store',
config:
{
model: 'MyApp.model.AutoSearchModel',
autoLoad:true,
id:'Contacts',
proxy:
{
type: 'ajax',
url: 'http://alucio.com.np/trunk/dev/sillydic/admin/api/word/categories/SDSILLYTOKEN/650773253e7f157a93c53d47a866204dedc7c363',
reader:
{
rootProperty:''
}
}
}
});
Model:
Ext.define('MyApp.model.AutoSearchModel', {
extend: 'Ext.data.Model',
requires: ['MyApp.model.AutoSearchModelMenu'],
config: {
fields: [
{name:'data', mapping: 'data'},
{name: 'name'},
],
},
});
and
Ext.define('MyApp.model.AutoSearchModelMenu', {
extend: 'Ext.data.Model',
config: {
fields: [
'name',
],
belongsTo: "MyApp.model.AutoSearchModel"
}
});
Controller:
Ext.define('MyApp.controller.SearchAutoComplete', {
extend : 'Ext.app.Controller',
config: {
profile: Ext.os.deviceType.toLowerCase(),
stores : ['MyApp.store.AutoSearchStore'],
models : ['MyApp.model.AutoSearchModel'],
refs: {
myContainer: 'mainPanel'
},
control: {
'mainPanel': {
activate: 'onActivate'
},
'mainPanel searchfield[itemId=searchBox]' : {
clearicontap : 'onClearSearch',
keyup: 'onSearchKeyUp'
}
}
},
onActivate: function() {
console.log('Main container is active--Search');
},
onSearchKeyUp: function(searchField) {
queryString = searchField.getValue();
console.log(this,'Please search by: ' + queryString);
var store = Ext.getStore('AutoSearchStore');
store.clearFilter();
if(queryString){
var thisRegEx = new RegExp(queryString, "i");
store.filterBy(function(record) {
if (thisRegEx.test(record.get('name'))) {
return true;
};
return false;
});
}
},
onClearSearch: function() {
console.log('Clear icon is tapped');
var store = Ext.getStore('AutoSearchStore');
store.clearFilter();
},
init: function() {
console.log('Controller initialized for SearchAutoComplete');
}
});
Json Data Looks Like:
"data":[
{
"name":"paint",
"author":"admin",
"word_id":"1",
"category":"Business",
"is_favourite":"yesStar"
},
{
"name":"abacus",
"author":"admin",
"word_id":"2",
"category":"Education",
"is_favourite":"yesStar"
},
{
"name":"abate",
"author":"admin",
"word_id":"3",
"category":"Education",
"is_favourite":"noStar"
},
{
"name":"testing adsf",
"author":"admin",
"word_id":"7",
"category":"Education",
"is_favourite":"noStar"
},
{
"name":"sprite",
"author":"admin",
"word_id":"6",
"category":"Business",
"is_favourite":"noStar"
},
{
"name":"newword",
"author":"admin",
"word_id":"8",
"category":"Architecture",
"is_favourite":"noStar"
}
]
})
If I type "A", then it displays No Matching Words, but I have words from "A" on json coming from server. How to solve this problem?
Any idea!
Code Sources Link
I don't know why you are using two models but just one thing you need to specify in AutoSearchStore :
reader:
{
rootProperty:'data'
}
instead of
reader:
{
rootProperty:''
}
to get the expected results in the list.
Hope this will be helpful :)