I want to query by using where in object with prisma and mongo
Here is my prisma schema
model Member {
id String #id #default(auto()) #map("_id") #db.ObjectId
bank BankInfo
##map("members")
}
type BankInfo {
bankNo String
}
const member = await this.prisma.member.findFirst({
where: { bank: { bankNo: 'test' } },
});
I got an error
Error:
Invalid prisma.member.findFirst() invocation:
You can try to use equal operator ($eq) like that :
const member = await this.db.member.find({
bank: { $eq: { bankNo: 'test' } }
})
I am trying to implement updation using prisma.
here is my data structure.
{
"name":"toy",
"data":{
"sports":{
"currentState":"false",
"oldState":"true"
}
}
Here is my logic to update currentState from false to true.
const updatedSource = await prisma.sources.update({
where: {
name: 'toy'
},
data: {
data: {
update:{
sports: {
currentState: "true"
}
}
}
},
})
Here is the schema file:
type SourcesData {
sports SourcesDataState
}
type SourcesDataState {
currentState String
oldState String
}
model sources {
id String #id #default(auto()) #map("_id") #db.ObjectId
data SourcesData
name String #unique
}
The above logic updates the currentState field but deletes the oldState field from the database.
Please guide me on how to update currentState in a way that oldState data persists.
When I do a nested object update inside an array in a Document. Does Mongo DB Engine needs to fetch and parse the whole document update the field and reinsert the document ?
db.ControllerPointCollection.updateOne({
"_id": "Ashutosh Das_MigrationTest_0_1_0"
}, {
$set: {
"Tables.$[t].Blocks.$[b].Points.$[p].Description": "Hey You"
}
}, {
arrayFilters: [{
"t.ID": 32
}, {
"b.ID": 268
}, {
"p.PointDefinitionID": 280
}]
})
Behind the scene, mongodb has a class called Model and inside Model class compose other behaviours with initializing other classes and one of them, I call it Sync which is implemented like this. this is not exact code, but you get the idea:
interface HasId {
id?: number; //optional
}
export class ApiSync<T extends HasId> {
constructor(public rootUrl: string) {}
// if user has Id, that means it is already stored in db, so we make a put request, if it does not then we make post
// so in mongoose, saving means Http request to db
save(data: T): AxiosPromise {
const { id } = data;
if (id) {
return axios.put(this.rootUrl + id, data);
} else {
return axios.post(this.rootUrl, data);
}
}
fetch(id: number): AxiosPromise {
return axios.get(this.rootUrl + id);
}
}
Inside my MongoDB repositories, entities have an _id: ObjectID type to be handled properly. However, I would like my domain entities to have a simple id: string attribute to avoid any dependencies on any database or framework. The solution I came up with so far looks as follows:
export interface Book {
id: string;
title: string;
}
// A MongodbEntity<Book> would now have an _id instead of its string id
export type MongodbEntity<T extends { id: string; }> = Omit<T, 'id'> & { _id: ObjectID; };
In my repository this would work:
async findOneById(id: string): Promise<Book | null> {
const res = await this.collection.findOneById({_id: new ObjectId(id)});
return res ? toBook(res) : null;
}
function toBook(dbBook: MongodbEntity<Book>): Book {
const {_id, ...rest} = dbBook;
return {...rest, id: _id.toHexString() };
}
What doesn't work is to make this behavior generic. A converter function like this:
function toDomainEntity<T extends {id: string}>(dbEntity: MongoDbEntity<T>): T {
const {_id, ...rest} = dbEntity;
return {...rest, id: _id.toHexString() };
}
leads to an error described here.
What I am looking for is either a working solution for the generic toDomainEntity function or a different (generic) approach that would let me decouple my domain entity types from MongoDB's _id: ObjectID type.
I am working on implementing a node interface for graphql -- a pretty standard design pattern.
Looking for guidance on the best way to implement a node query resolver for graphql
node(id ID!): Node
The main thing that I am struggling with is how to encode/decode the ID the typename so that we can find the right table/collection to query from.
Currently I am using postgreSQL uuid strategy with pgcrytpo to generate ids.
Where is the right seam in the application to do this?:
could be done in the primary key generation at the database
could be done at the graphql seam (using a visitor pattern maybe)
And once the best seam is picked:
how/where do you encode/decode?
Note my stack is:
ApolloClient/Server (from graphql-yoga)
node
TypeORM
PostgreSQL
The id exposed to the client (the global object id) is not persisted on the backend -- the encoding and decoding should be done by the GraphQL server itself. Here's a rough example based on how relay does it:
import Foo from '../../models/Foo'
function encode (id, __typename) {
return Buffer.from(`${id}:${__typename}`, 'utf8').toString('base64');
}
function decode (objectId) {
const decoded = Buffer.from(objectId, 'base64').toString('utf8')
const parts = decoded.split(':')
return {
id: parts[0],
__typename: parts[1],
}
}
const typeDefs = `
type Query {
node(id: ID!): Node
}
type Foo implements Node {
id: ID!
foo: String
}
interface Node {
id: ID!
}
`;
// Just in case model name and typename do not always match
const modelsByTypename = {
Foo,
}
const resolvers = {
Query: {
node: async (root, args, context) => {
const { __typename, id } = decode(args.id)
const Model = modelsByTypename[__typename]
const node = await Model.getById(id)
return {
...node,
__typename,
};
},
},
Foo: {
id: (obj) => encode(obj.id, 'Foo')
}
};
Note: by returning the __typename, we're letting GraphQL's default resolveType behavior figure out which type the interface is returning, so there's no need to provide a resolver for __resolveType.
Edit: to apply the id logic to multiple types:
function addIDResolvers (resolvers, types) {
for (const type of types) {
if (!resolvers[type]) {
resolvers[type] = {}
}
resolvers[type].id = encode(obj.id, type)
}
}
addIDResolvers(resolvers, ['Foo', 'Bar', 'Qux'])
#Jonathan I can share an implementation that I have and you see what you think. This is using graphql-js, MongoDB and relay on the client.
/**
* Given a function to map from an ID to an underlying object, and a function
* to map from an underlying object to the concrete GraphQLObjectType it
* corresponds to, constructs a `Node` interface that objects can implement,
* and a field config for a `node` root field.
*
* If the typeResolver is omitted, object resolution on the interface will be
* handled with the `isTypeOf` method on object types, as with any GraphQL
* interface without a provided `resolveType` method.
*/
export function nodeDefinitions<TContext>(
idFetcher: (id: string, context: TContext, info: GraphQLResolveInfo) => any,
typeResolver?: ?GraphQLTypeResolver<*, TContext>,
): GraphQLNodeDefinitions<TContext> {
const nodeInterface = new GraphQLInterfaceType({
name: 'Node',
description: 'An object with an ID',
fields: () => ({
id: {
type: new GraphQLNonNull(GraphQLID),
description: 'The id of the object.',
},
}),
resolveType: typeResolver,
});
const nodeField = {
name: 'node',
description: 'Fetches an object given its ID',
type: nodeInterface,
args: {
id: {
type: GraphQLID,
description: 'The ID of an object',
},
},
resolve: (obj, { id }, context, info) => (id ? idFetcher(id, context, info) : null),
};
const nodesField = {
name: 'nodes',
description: 'Fetches objects given their IDs',
type: new GraphQLNonNull(new GraphQLList(nodeInterface)),
args: {
ids: {
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(GraphQLID))),
description: 'The IDs of objects',
},
},
resolve: (obj, { ids }, context, info) => Promise.all(ids.map(id => Promise.resolve(idFetcher(id, context, info)))),
};
return { nodeInterface, nodeField, nodesField };
}
Then:
import { nodeDefinitions } from './node';
const { nodeField, nodesField, nodeInterface } = nodeDefinitions(
// A method that maps from a global id to an object
async (globalId, context) => {
const { id, type } = fromGlobalId(globalId);
if (type === 'User') {
return UserLoader.load(context, id);
}
....
...
...
// it should not get here
return null;
},
// A method that maps from an object to a type
obj => {
if (obj instanceof User) {
return UserType;
}
....
....
// it should not get here
return null;
},
);
The load method resolves the actual object. This part you would have work more specifically with your DB and etc...
If it's not clear, you can ask! Hope it helps :)