How do I query MongoDB to find all records which contain a particular array of objects? - mongodb-query

I am implementing tagging functionality in my Angular MEAN stack app and so want to query the DB to retrieve all objects (in this case "NFR"s) which have one or more of those tags ("Tag" objects). Thus I have NFR objects which may contain an array of Tag objects. I have tried a number of MongoDB find queries which return nothing despite tagged records existing.
Here are some code snippets (Mongoose schema defs for NFR and Tag). Thanks very muchly in advance :-).
Katie
NFR schema:
import * as mongoose from "mongoose";
import {Tag} from "../../app/main/models/tag";
let NFR = new mongoose.Schema({
category: String,
subCategory: String,
nfr: String,
acceptanceTest: String,
source: String,
status: String,
creationDate: Date,
createdBy: String,
changeLog: String,
tags: [{
type: Tag
}]
});
Tag schema
import * as mongoose from "mongoose";
let Tag = new mongoose.Schema({
name: String,
source: String,
creationDate: Date,
_id: String
});
In the database the NFR object to search on contains two Tag objects via object id reference .

Thanks Veeram, I had to move the Tag mongoose class inside the NFR one to get it creating the associated Tag object properly (which I can now search on). This is a bad hack, not sure why it doesn't work the proper way but it will do for now.

Related

Reddis Stack JSON: Nested JSON vs namespace usage recommendation

The redisinsight workbench use namespaces to store JSON objects, such as:
school_json:1 -> {...}
school_json:2 -> {...}
...
But I am asking myself if that is the way to go when dealing with JSON documents. The JSON examples at https://redis.io/docs/stack/json/path/ showcase how to store items in a nested JSON object called store.
In my case I would like to store users. At first I had a structure where a toplevel key users exists such as
users -> {
1: { // actually I'm using a uuid here
username: "Peter"
email: ... // etc.
},
2: {
username: "Marie",
email: ...
}
}
Or should I use namespaces here as well which would look somewhat like:
users:1 -> {
username: "Peter"
email: ...
},
users:2 -> {
username: "Marie",
email: ...
}
I assume that using namespaces would have performance benefits over nested JSON but the example in the redis documentation which uses a nested JSON object to store several items confused me if that is actually true.
I found this answer but that is discussing redis, not redis stack using JSON (which may come with other optimizations).
Thanks in advance!

Kotlin- Is there any way to update a single field in collection item in Kotlin without foreach?

I am working on Android application using kotlin. I am pretty much new to kotlin and I have the following scenario.
I have the list of users in a List collection object with the fields such as firstName , lastName, mobile and hasDeleted
var myList: List<Users>
myList = <I have list of users here>
I would like to update only one flag hasDeleted with the value true for each Users.
I understand that we can use foreach to update the value. But, I would like to know if any other approach I can follow.
The only reason for not using forEach is if your Users object is immutable (which you should at least consider) and it is a data class defined as follows:
data class Users(val firstName: String,
val lastName: String,
val mobile: String,
val hasDeleted: Boolean)
If this is what you have, then map is your best option, since you can no longer change a Users object with hasDeleted = true because they are not mutable. In this case, you should use the following which will return a list with the updated Users objects.
myList.map { it.copy(hasDeleted = true) }
Other than this specific case, I see no good reason to avoid using forEach.
You can simply use map for it:
myList.map { it.hasDeleted = true }
it will update all hasDeleted as true in the list.
Yes you can do it with the following approach
var myList: List<User>
myList.map { it.hasDeleted = true}
The map will replace the value of hasDeleted for all the list items to true/false, whatever you will provide.
Here is a tested sample with expected results.

PRISMA: Getting type error on where clause in update method

Have a specific Prisma ORM library error that I need help with.
I have created a migration and pushed it to a postgres db.
I have generated the client model for Prisma and am able to findAll and insert data using the create method.
Where I am having trouble is the update method.
Here's my code
app.post("/articles/:title", async (req: Request, res: Response) => {
const article = await prisma.article.update({
where: { title: req.params.title },
data: { title: req.body.title, content: req.body.content },
})
res.send('The article was posted sucessfully.' + article)
})
I am getting the following error which makes me think that the client is not finding a type 'title' when using the where argument.
app.ts:65:14 - error TS2322: Type '{ title: string; }' is not assignable to type 'ArticleWhereUniqueInput'.
Object literal may only specify known properties, and 'title' does not exist in type 'ArticleWhereUniqueInput'.
65 where: { title: req.params.title },
~~~~~~~~~~~~~~~~~~~~~~~
node_modules/.prisma/client/index.d.ts:784:3
784 where: ArticleWhereUniqueInput
~~~~~
The expected type comes from property 'where' which is declared here on type 'Subset<ArticleUpdateArgs, ArticleUpdateArgs>'
Has anyone else had this issue?
I tried to introspect the database just to make sure the database was captured exactly as is, with title and content fields and then generated the client again.
Many thanks
James
Found the answer: Post answer was a response from Antonie
The fields in
where
needs to be unique.
If you can make some field, let's say date #unique (date: DateTime! #unique), and use that for your where in the upsert, I think it would work (tested on my local).
Use .(find/update/delete)Many() if you are trying to query with multi values.

Designing a GraphQL schema for an analytics platform

I'm just starting to explorer GraphQL as an option for my analytic platform API layer.
My UI is mainly built from tables and charts. most of the times the data represents some DB columns grouped by a dimension.
I've found the following article https://www.microsoft.com/developerblog/2017/09/28/data-independent-graphql-using-view-model-based-schemas/ from Microsoft, describing their take on how suck GraphQL schemas should be designed (see below).
type Query {
channels(source: String!, query:String!, appId:String!, apiKey:String!): [Channel]
lineCharts(source: String!, query:String!, appId:String!, apiKey:String!, filterKey:String, filterValues:[String]): [LineChart]
pieCharts(source: String!, query:String!, appId:String!, apiKey:String!): [PieChart]
barCharts(source: String!, query:String!, appId:String!, apiKey:String!, filterKey:String, filterValues:[String]): [BarChart]
}
type Channel {
name: String
id: Int
}
type LineChart {
id: String
seriesData : [Series]
}
type PieChart {
id: String
labels: [String]
values: [Int]
}
type BarChart {
id: String
seriesData : [Series]
}
type Series {
label: String
x_values: [String]
y_values: [Int]
}
It seems to me that this design is strict, forcing any new chart to be added to the root Query. How can the schema be more generic, without loosing GraphQL benefits?
You could do something with union types and inline/fragments
union Chart = LineChart | PieChart | BarChart
type Query {
charts(
source: String!
query: String!
appId: String!
apiKey: String!
filterKey: String
filterValues: [String]
): [Chart]
}
Then you can have your charts resolver bring ALL the charts and write your queries like
fragment Identifiers on Chart {
__typename
id
}
query {
charts(...) {
...on LineChart {
...Identifiers
seriesData
}
...on PieChart {
...Identifiers
labels
values
}
...on BarChart {
...Identifiers
seriesData
}
}
}
The Identifiers will provide you with some information about what type you're dealing with and it's id, but you can extend it to whatever you like as long as those fields are common to all types on that union (or you can spread it only on some of the types).
There are 2 ways you can go about if you don't want to bring in all the charts:
Add inline fragments for only the types you want, but the rest will still be there, in the form of empty objects.
Pass another argument to the resolver representing the type/s you want
P.S. You can get as granular as you like, there are also interfaces and input types.

mean.js uses require without var

Have a question with regards to the default meanjs app from yeoman.
Inside the express.js file it has a statement like so:
// Globbing model files
config.getGlobbedFiles('./app/models/**/*.js').forEach(function(modelPath) {
require(path.resolve(modelPath));
});
Now I understand that it gets all the .js files inside the path "./app/models/", but what I am trying to understand is the alone standing
require(path.resolve(modelPath));
How is the require function being used without it being set to a "var"?
An example of one of these included files is like this:
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
/**
* Article Schema
*/
var ArticleSchema = new Schema({
created: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true,
required: 'Title cannot be blank'
},
content: {
type: String,
default: '',
trim: true
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Article', ArticleSchema);
This file doesn't expose anything.
So why is the require being called with a "var" and without the contents exposing a function?
How will this allow for the contents to be used later?
The code in the express.js file executes the contents of your model files. The anatomy of a MEAN.js model file is the following;
Load the mongoose and schema packages, along with all your included
models (if any).
Declare the schema for the given model
Register the given schema under the model name (Article for the given example).
There is nothing to return, hence the lack of any variable assignment in the express.js file. From now on you can call models by the label you assigned in the third part. Therefore, in your controller, you would write something like;
var articles = Article.query();
This line of code would load up the Article schema and run the provided query() method in your back-end (which by default returns all the instances in the database under that model).
In general, remember; not all functions return something.