Querying associated models using MEAN stack - javascript

I’m trying to setup an model association using MEAN where an Epic has many Tasks. I’m creating the Epic first then associating it when creating a task. The task data model looks like this with the Epic associated:
task:
{ name: 'my first task',
epic:
{ name: 'My fist epic',
_id: 52f511c605456ba4c936180d,
__v: 0},
_id: 52f511d605456ba4c936180e,
__v: 0 } }
In my public Epics controller I’m trying to query for all the tasks with the current Epic’s ID but I’m I’m not having much luck. The query below returns ALL tasks instead of the tasks associated with my Epic.
Tasks.query({“epic._id": $routeParams.epicId}, function(tasks) {
$scope.tasks = tasks;
});
Is there a better way to do association and retrieval using MEAN? I’m a bit of a noob.
Thanks in advance!
EDIT:
I've playing around with the idea of updating the epic when a new task is created. In app/controllers/tasks.js I have this code that doesn't work.
exports.create = function (req, res) {
var task = new Task(req.body)
Epic.find(req.body.epic.id, function (err, epic) {
if (err) return next(err)
epic.tasks.push(task.id);
epic.save();
})
task.save()
res.jsonp(task)
}

Are you also using mongoose? I would use the "ref" and "populate".
First you have a TaskSchema.
var TaskSchema = new Schema({ ... });
mongoose.model('Task', TaskSchema);
add the model etc, then you you reference it in your other schema. I'll add an example of 1 or multiple task(s).
var Schema = new Schema({
task: {
type: Schema.ObjectId,
ref: 'Task'
},
tasks: [
{ type: Schema.Types.ObjectId, ref: 'Task'}
]
});
and then to call it with populate.
this.findOne({
_id: id
}).populate('tasks').exec(cb);

It looks like you need help debugging xhr. Let's trace the steps:
Is your request making it to the server?
Is it arriving at the correct express route?
Is your server-side code performing the correct find operation against Mongo?
Is Mongo returning the right results?
Are you writing the results from Mongo into the response correctly?
Are you able to see the response on the client by inspecting the network traffic using your browser's dev tools?
Are you handling the promise success correctly?
You'll need to post more info and code to know where the problem lies.

Related

Mongoose-fuzzy-searching returns empty array unless query is empty

I am working on a wiki-like website component and I am trying to implement a fuzzy search. I found a popular Node.js plugin on npmjs for a fuzzy search of a cloud mongoDB database handled with Mongoose. I installed and saved mongoose-fuzzy-searching and hooked it up to my model and route. Then I updated all of the models, resaving each's value for the field I wanted to index. I can seem to call the function on a model, and it seems like there's an index on MongoDB Atlas, but it returns an empty array instead of any results. 2 questions:
Am I doing something wrong, or is there something I am missing?
Is there a better node library that's free? (*Free on heroku, which I think eliminates flexsearch as an option)
Here's my code.
Model:
const mongoose = require("mongoose"),
mongoose_fuzzy_searching = require('mongoose-fuzzy-searching'),
Schema = mongoose.Schema;
const IssueTemplateSchema = new Schema({
name: String,
info: String,
image: String,
tags: [{type: Schema.Types.ObjectId, ref: "Tag"}],
active: {type: Boolean, default: true},
instances: [{type: Schema.Types.ObjectId, ref: "LocalIssue"}],
issues: {type: Schema.Types.ObjectId, ref: "Issuegraph" },
});
IssueTemplateSchema.plugin(mongoose_fuzzy_searching, { fields: ['name'] });
module.exports = mongoose.model("IssueTemplate", IssueTemplateSchema);
An update to all of the issuetemplate models:
const express = require('express'),
router = express.Router(),
Issue = require('../api/issue/issue.template');
router.get("/createIndex", async (req, res) => {
Issue.find({}, async (err, issues) => {
if(err){console.log(err)}else {
for(issue of issues){
if(err){console.log(err)}else{
const name = issue.name;
await Issue.findByIdAndUpdate(issue._id, {name: name}, {strict: false});
}
}
}
});
return res.send("done");
});
Route:
router.get("/search", (req, res) => {
console.log(req.query.target);
let searchTerm = "";
if(req.query.target){
searchTerm = decodeURIComponent(req.query.target.replace(/\+/g, ' '));
}
Issue.fuzzySearch(searchTerm, (err, issue)=> {
if(err){
console.log(err);
res.send("Error fuzzy searching: " + err);
} else {
returnResult(issue);
}
});
function returnResult(result) {
console.log(result);
return res.send(result);
}
});
When I ran
npm install --save mongoose-fuzzy-searching
I received an error saying it needed mongoose 5.10, and I have 5.11, but it seemed to at least plug in. Can't see why When I send a request through Postman, I receive an empty array. If I leave the query blank, then I get everything. I have reset Node and am using mongoDB Cloud, where I see an index has been created. Is there perhaps a reset of the cloud database I would need to do (I don't know of such a thing), or is resetting the server enough? My knowledge level is: studying to be a freelance web developer and would appreciate any general tips on best practice, etc.
Mongoose need to define schema. which makes it slow and find() method is good for development, not for production level. Also ,This Process is outdated. You are working on MongoDB. if you need search then take a look into MongoDB atlas Full Text-Search.It includes all of those searching features like: autocomplete, Fuzzy Search everything.
It seems like my update operation was not actually updating the field I wanted to update, because findByIdAndUpdate() returns a query and I wasn't executing that query (with .exec() ). Await was also being used incorrectly because its purpose is not just to pause in an async function like I thought, but to wait for a promise to fulfill. A query is not a promise, and await is specifically for promises. Before I learned these details, I solved my problem in another way by using .find() , then .markModified("name") , then .save() . Once I did that, it all worked!

associating a GridFS-Stream file to a Schema with Mongoose

I am writing an API for my application, using Mongoose, Express, and GridFS-Stream. I have a Schema for the articles the user will create:
var articleSchema = mongoose.Schema({
title:String,
author:String,
type: String,
images: {type: Schema.Types.ObjectId, ref: "fs.files"},
datePublished: { type: Date, default: Date.now },
content: String
})
var Article = mongoose.model("article", articleSchema, "articles");
and my grid-fs set up for when a user uploads an image:
api.post('/file', fileUpload.single("image"), function(req, res) {
var path = req.file.path;
var gridWriteStream = gfs.createWriteStream(path)
.on('close',function(){
//remove file on close of mongo connection
setTimeout(function(){
fs.unlink(req.file.path);
},1000);
})
var readStream = fs.createReadStream(path)
.on('end',function(){
res.status(200).json({"id":readStream.id});
console.log(readStream);
})
.on('error',function(){
res.status(500).send("Something went wrong. :(");
})
.pipe(gridWriteStream)
});
Right now it's set up to when the user chooses an image, it automatically uploads it via gridfs-stream, puts it in a temp folder, then deletes it when it is uploaded to the mongo server, and in the console returns what the ObjectId is. Well thats all find and dandy, but we need to associate this ID with the articleSchema, so when we call that article in the app, it will display the associated image.
on our creation/update of an article when the user hits submit:
createArticle(event) {
event.preventDefault();
var article = {
type: this.refs.type.getValue(),
author: this.refs.author.getValue(),
title: this.refs.title.getValue(),
content: this.refs.pm.getContent('html')
};
var image = {
images: this.refs.imageUpload.state.imageString
};
var id = {_id: this.refs.id.getValue()};
var payload = _.merge(id, article, image);
var newPayload = _.merge(article, image)
if(this.props.params.id){
superagent.put("http://"+this.context.config.API_SERVER+"/api/v1.0/article/").send(payload).end((err, res) => {
err ? console.log(err) : console.log(res);
});
} else {
superagent.post("http://"+this.context.config.API_SERVER+"/api/v1.0/article").send(newPayload).end((err, res) => {
err ? console.log(err) : console.log(res);
this.replaceState(this.getInitialState())
this.refs.articleForm.reset();
});
}
},
So what I need it to do, is call the ID, of the image I just uploaded to the images section of my schema when the user hits submit on the creation of an article. I've tried doing a readstream on submit, but again, the problem is I can't get the ID, or the filename, to be able to associate it.
They are getting stored in the mongo database, it creates fs.files and fs.chunks, but for the life of me I can't figure out how to get that data and attach it to a schema, or just even get the data out, without knowing the ObjectId.
So how do I call out the objectid from fs.files or fs.chunks to attach it to the schema? and in the schema how do I reference the fs.files or chunks? so it knows what the objectid is associated with?
I can provide anymore data, if what I have is to vague, I have a nasty habit of doing that. sorry.
So I ended up solving my problem, might not be the best solution, but it works until I can get a better solution.
in the API changed
res.status(200).json({"id":readStream.id});
to
res.status(200).send(readStream.id);
in my component, I then set the state to the response.body, which will set the state of the id of the image uploaded. So in the main view, i reference the image uploading component, and set the image state of my view to the id state of my component, and viola, I now have the id in my database, associated with the newly created article.
the problem i then ran into was, it didn't know what to reference. so I attached the API URL to the id, and it acts like it is referencing a URL img, and renders the image correctly.
Again, this may not be the best way to go about this, in fact, I am pretty sure it isn't, but It is whats working for now until I can either reference the database correctly, or create a new component that just stores all the images on server and reference them that way, much like wordpress.

Sails.js Waterline query by association

I'm developing and app with Sails.js and using Waterline orm for db. I'm developing functionality for users to do friend requests and other similar requests to each other. I have following URequest model for that:
module.exports = {
attributes: {
owner: {
model: 'Person'
},
people: {
collection: 'Person'
},
answers: {
collection: 'URequestAnswer'
},
action: {
type: 'json' //TODO: Consider alternative more schema consistent approach.
}
}
};
Basically owner is association to Person who made the request and people is one-to-many association to all Persons who the request is directed. So far fine.
Now I want to have a controller which returns all requests where certain user is involved in meaning all requests where user is either in owner field or in people. How I do query like "give me all rows where there is association to person P" ? In other words how I ca know which URequest models have association to a certain Person?
I tried something like this:
getRequests: function (req, res) {
var personId = req.param('personId');
URequest.find().where({
or: [
{people: [personId]}, //TODO: This is not correct
{owner: personId}
]
}).populateAll().then(function(results) {
res.json(results);
});
},
So I know how to do the "or" part but how do I check if the personId is in people? I know I should somehow be able to look into join-table but I have no idea how and couldn't find much from Waterline docs relating to my situation. Also, I'm trying to keep this db-agnostic, though atm I'm using MongoDB but might use Postgres later.
I have to be honest this is a tricky one, and, as far as I know what you are trying to do is not possible using Waterline so your options are to write a native query using query( ) if you are using a sql based adapter or native otherwise, or try doing some manual filtering. Manual filtering would depend on how large of a dataset you are dealing with.
My mind immediately goes to reworking your data model a bit, maybe instead of a collection you have a table that stores associations. Something like this:
module.exports = {
attributes: {
owner: {
model: 'URequest'
},
person: {
model: 'Person'
}
}
Using the sailsjs model methods (like beforeCreate) you could auto create these associations as needed.
Good Luck, I hope you get it working!

How to implement custom routes in sailsjs

I'm trying to understand sails.js. Firstly I try generate new api.
This is my code of models and controller
Coutries.js
module.exports = {
attributes: {
title:{
type:'string',
unique:true,
primaryKey:true
},
cities:{
collection:'Cities',
via:'country'
}
}
};
Cities,js
module.exports = {
attributes: {
title: {
type:'string',
unique:true,
primaryKey:true
},
country:{
model:'Countries',
type:'String'
},
description: {
type:'string'
}
}
};
Next in routes.js I wrote
'get /countries':'CountriesController.getAllCountries'
I need a list of countries.
I can not understand how to implement the function getAllCountries in CountriesController.js.
I use a local db in tmp directory.
Please, can somebody understand me in details how I can do this?
Also for understanding tell me how to implement a function addNewCountries and for example updateCitiesDescription.
Thanks and sorry for my english)
With sails, if you have a function to handle your routes, you create it inside api/controllers/CountriesController as a method.
For routes:
'get /countries':'CountriesController.getAllCountries'
Countries Controller:
module.exports = {
getAllCountries: function (req, res, next){
return Country.getAllCountries(function success(countries){
//handle your success logic e.g: return res.view("countries", {data: countries});
}, function errorHandle(error){
//error handling
})
}
}
Countries Model:
//inside your module.exports in api/models/Countries add this method
getAllCountries: function(cb, err){
Country.find({}).then(cb).catch(err);
}
To summarize, you use your controller method to contact the model and pass a success and error handling functions that will return an appropriate view.
Well, if your aim is to just view the list of countries then Sails has got you covered. It provides blueprint API's which you can directly use to query your db and view the response as JSON.
For example, you can call
http://localhost:1337/countries
to view all the countries in the db. Similarly you can carry out other queries as well directly using the API. Find more info about it here
However, if you would still like to query the database yourself to get the hang of it, what you've done so far is on the right track.
In your CountriesController, create a new action called "getAllCountries"
getAllCountries: function(req, res) {
Countries.find().exec(function(err, countries){
res.json(countries);
});
});
Your route basically tries to find a method named "getAllCountries" in the controller "CountriesController" and redirects your request to that action.
Upon receiving the call, you just fetch the list of countries from the database using waterline's query language and return the JSON back to the user.
A friendly advice, avoid naming your models in plural. For example, if you are trying to maintain countries and cities in your db, then name the models "Country" and "City".

Create and read a record in Ember.js

I'm working with Emeber.js framework; I've created an object like this:
myApp.user=Ember.Object.extend({
name:null,
state:false
});
I've also defined an Ember model this way:
myApp.Wuser = DS.Model.extend({
nome: DS.attr('string'),
user: DS.attr('mycustomtype') // i want put here a mycustom type (user)
});
The question is: how can I create a record? I've tried to write this:
myApp.Wuser.createRecord({nome:"aaa",user:myApp.user.create()});
but an error occurred; do you know how to create a record and how to read it?
Thanks in advance!
You create a record on your store.
record = this.get('store').createRecord(MyApp.User, {name: 'Luke'})
To persist it to your server:
this.get('store').commit();
You can also do this for a transaction:
record = transaction.createRecord(MyApp.User, {name: 'Luke'})

Categories