Meteorjs collection can't be accessed /w async when used with 'export const' - mongodb

Okay I am getting into the basics of meteor but I still can't figure what is going on when I define my collections for both server/client using
// /lib/collections.js
import { Mongo } from 'meteor/mongo';
export const Info = new Mongo.Collection('info');
export const Name = new Mongo.Collection('name');
export const Dates = new Mongo.Collection('date');
but then I run on my server a publish
// /server/main.js
Meteor.publish('insertByName', function(query) {
AsyncAPICall.findName(nameVar, Meteor.bindEnvironment(function(err, names) {
Name.upsert(query.blob, query.set);
}));
});
I get
Exception in callback of async function: ReferenceError: Name is not defined
if I edit my collection to
// lib/collections.js
import { Mongo } from 'meteor/mongo';
Info = new Mongo.Collection('info');
Name = new Mongo.Collection('name');
Dates = new Mongo.Collection('date');
the upsert works fine. BUT there is a problem with retrieving the data on the client with subscribe
I run a
// /server/main.js
Meteor.publish('getName_publish', function () {
return Name.find();
});
and
// /client/main.js
import {
Summoners,
Champions,
SummonersByName
} from '../lib/collections.js';
import '/client/template/page.js';
// /client/template/page.js
Template.page.onCreated(function pageOnCreated() {
Meteor.subscribe('getName_publish');
});
Template.page.helpers({
byname() {
return Name.find({}, { sort: { updated_at: -1 } }); //{}, { sort: { updated_at: -1 } }
},
});
my object ends up empty.
Basically if there is export const I can't upsert to the Mongo collection, if there isn't I can't retrieve the records.
Update If I use Name.find().fetch() in the browser console it returns the object as it's supposed to, but not inside the Template.page.helpers or on Template.page.onCreated

Related

Issue testing RTK Query: The preloadedState argument passed to createStore has unexpected type of "array"

I'm learning RTK Query.
So, in a test, I have the following error:
The preloadedState argument passed to createStore has unexpected type of "array". Expected argument to be an object with the following keys: "queries", "mutations", "provided", "subscriptions", "config"
This is my test:
test("Can use preloadedState", () => {
const initialPosts = [
{
id: 1,
body: "Lorem ipsum",
},
];
// wrap component with custom render function
renderWithProviders(<GenericList />, {
preloadedState: {
postsSlice: initialPosts,
},
});
const loremIpsum = screen.getByText(/lorem ipsum/i);
expect(loremIpsum).toBeInTheDocument();
});
I have followed this tutorial https://redux.js.org/usage/writing-tests#preparing-initial-test-state.
This is my test-utils.js file:
import React from 'react'
import { render } from '#testing-library/react'
import { Provider } from 'react-redux'
import { setupStore } from '../../store/index'
import { setupListeners } from '#reduxjs/toolkit/dist/query'
export function renderWithProviders(
ui,
{
preloadedState = {},
// Automatically create a store instance if no store was passed in
store = setupStore(preloadedState),
...renderOptions
} = {}
) {
setupListeners(store.dispatch);
function Wrapper({ children }) {
return <Provider store={store}>{children}</Provider>
}
return { store, ...render(ui, { wrapper: Wrapper, ...renderOptions }) }
}
This is my store:
import { configureStore } from "#reduxjs/toolkit";
import { postsSlice } from "../features/postsSlice";
export const setupStore = preloadedState => {
return configureStore({
reducer: {
[postsSlice.reducerPath]: postsSlice.reducer,
},
preloadedState,
middleware: getDefaultMiddleware =>
getDefaultMiddleware({
immutableCheck: false,
serializableCheck: false,
}).concat(postsSlice.middleware),
})
}
And finally this is the postsSlice
import { createApi, fetchBaseQuery } from "#reduxjs/toolkit/query/react";
export const postsSlice = createApi({
// Reducer Path it's name shown on Redux Tab
reducerPath: "postsSlice",
baseQuery: fetchBaseQuery({
baseUrl: process.env.REACT_APP_BACKEND_URL,
}),
// With tag type we can invalidate cache
tagTypes: ['posts'],
endpoints: (builder) => ({
getPosts: builder.query({
query: () => "/posts"
})
})
});
export const { useGetPostsQuery } = postsSlice;
You cannot just make up some random contents for your initialState, it has to be exactly the structure of your Redux state. And for RTK Query, that is a very complex internal structure that you should probably not mock (it could change in another version!).
Honestly, to your last question, this is a step backwards - if you want to test RTK Query, test it with a normal Redux store and mock the api.
All you were missing was to wait in your test until the result was rendered.
Faking internal data structures means that your test will just test a very small part of what actually happens.

Opening Mongoose connection in AdonisJS provider times out

I was following this article to use Mongo in AdonisJS 5 project.
I have an AdonisJS provider which I have created by node ace make:provider Mongo (it is registered in .adonisrc.json):
import { ApplicationContract } from '#ioc:Adonis/Core/Application'
import { Mongoose } from 'mongoose'
export default class MongoProvider {
constructor(protected app: ApplicationContract) {}
public async register() {
// Register your own bindings
const mongoose = new Mongoose()
// Connect the instance to DB
await mongoose.connect('mongodb://docker_mongo:27017/mydb')
// Attach it to IOC container as singleton
this.app.container.singleton('Mongoose', () => mongoose)
}
public async boot() {
// All bindings are ready, feel free to use them
}
public async ready() {
// App is ready
}
public async shutdown() {
// Cleanup, since app is going down
// Going to take the Mongoose singleton from container
// and call disconnect() on it
// which tells Mongoose to gracefully disconnect from MongoBD server
await this.app.container.use('Mongoose').disconnect()
}
}
My model is:
import { Schema, model } from '#ioc:Mongoose'
// Document interface
interface User {
email: string
}
// Schema
export default model(
'User',
new Schema<User>({
email: String,
})
)
Controller:
import { HttpContextContract } from '#ioc:Adonis/Core/HttpContext'
import User from 'App/Models/User'
export default class UsersController {
public async index({}: HttpContextContract) {
// Create a cat with random name
const cat = new User({
email: Math.random().toString(36).substring(7),
})
// Save cat to DB
await cat.save()
// Return list of all saved cats
const cats = await User.find()
// Return all the cats (including the new one)
return cats
}
}
And it is timeouting.
It is working, when I open the connection in controller like this though:
import { HttpContextContract } from '#ioc:Adonis/Core/HttpContext'
import User from 'App/Models/User'
import mongoose from 'mongoose'
export default class UsersController {
public async index({}: HttpContextContract) {
await mongoose.connect('mongodb://docker_mongo:27017/mydb')
// Create a cat with random name
const cat = new User({
email: Math.random().toString(36).substring(7),
})
// Save cat to DB
await cat.save()
// Return list of all saved cats
const cats = await User.find()
// Close the connection
await mongoose.connection.close()
// Return all the cats (including the new one)
return cats
}
}
I have just created an AdonisJS provider, registered it in .adonisrc.json, created a contracts/Mongoose.ts with typings, and use the model in controller.
Any idea? I'm stuck for a day with this.
Thanks
I managed to resolve this issue by not storing mongoose in a variable. It seems the mongoose variable you declare in your MongoProvider is the root of your timeout error.
So I did as follow :
export default class MongoProvider {
constructor(protected app: ApplicationContract) {}
public async register() {
await mongoose.connect('mongodb://localhost:27017/dbName')
this.app.container.singleton('Mongoose', () => mongoose)
}
public async boot() {
// All bindings are ready, feel free to use them
}
public async ready() {
// App is ready
}
public async shutdown() {
await this.app.container.use('Mongoose').disconnect()
}
}
If someone would be interested:
with the help of the article author the reason why it is not working was missing Mongoose when creating the model (Mongoose.model instead of just model:
export default Mongoose.model(
'User',
new Schema<User>({
email: String,
})
)
I followed this article too, and I have the same issue you discussed. but resolved this by importing mongoose in my model a little differently.
import mongoose in the model like this import Mongoose, { Schema } from '#ioc:Mongoose' instead of import { Schema, model } from '#ioc:Mongoose'
Example:
import Mongoose, { Schema } from '#ioc:Mongoose'
// Document interface
interface User {
email: string
}
// Schema
export default model(
'User',
new Schema<User>({
email: String,
})
)

NestJS: This operation is not supported by Mongodb driver

I am trying to get all the elements from database but stucking with this error that says:
This operation is not supported by Mongodb driver.
I am using MongoDB along with Mongoose to interact with database.
Here is my code where the error happening:
import { GetTasksFilterDto } from './dto/get-tasks-filter.dto';
import { TaskStatus } from './task-status.enum';
import { CreateTaskDto } from './dto/create-task.dto';
import { TaskEntity } from './task.entity';
import { Repository, EntityRepository } from 'typeorm';
#EntityRepository(TaskEntity)
export class TaskRepository extends Repository<TaskEntity> {
async getTasks(filterDto: GetTasksFilterDto): Promise<TaskEntity[]> {
const { status, search } = filterDto;
const query = this.createQueryBuilder('task');
// The error happen in this line
const tasks = await query.getMany();
return tasks;
}
}
Will this TypeORM MongoDB Documentation did the job for me.
The issue was that, the way I am doing it is wrong, mongodb doesn't support that way of queries, instead I must use the proper way to do it which by using MongoRepository that allows us to create a manager for any Entity.
The code below shows how I solved the problem:
async getTasks(filterDto: GetTasksFilterDto): Promise<TaskEntity[]> {
const { status, search } = filterDto;
const manager = getMongoRepository(TaskEntity);
const tasks = await manager.find({
status: status,
where: {
$or: [
{ text: Like(`%${search.toString()}%`) },
{ title: Like(`%${search.toString()}%`) },
],
},
});
return tasks;
}

The correct way to create collection during mongoose transaction

How to autocreate collection during mongoose transaction if the collection was not created yet?
I'm aware of mongoose limitation that restricts user to create (or delete) mongoose collections during open transaction session.
Also, I was able to find 3 possible solutions on how to fix that:
1. autoCreate option
2. Model.init() method
3. Model.createCollection() method
Which one to use? Without losing indexes etc.
app.models.ts
import { model, Schema } from 'mongoose';
const UserSchema = new Schema<UserDocument>({
name: {
type: Schema.Types.String,
required: true,
}
}); // { autoCreate: true } <-- ???
export const UserModel = model<UserDocument>('User', UserSchema);
app.ts
import { startSession } from 'mongoose';
import { UserModel } from './app.models.ts';
async function createUser() {
// await UserModel.createCollection(); ??
// or
// await UserModel.init(); ??
const session = await startSession();
sesssion.startTransaction();
try {
const [user] = await UserModel.create([{ name: 'John' }], { session });
await session.commitTransaction();
return user;
} catch (error) {
await session.abortTransaction();
} finally {
session.endSession()
}
}
foo();
If a collection does not exist, MongoDB creates the collection when you first store data for that collection. You can also explicitly create a collection with various options, such as setting the maximum size or the documentation validation rules.
Anyway, mongoose takes care of indexes, collection, etc...
you just need to define the collection name: https://mongoosejs.com/docs/guide.html#collection
const UserSchema = new Schema<UserDocument>({
name: {
type: Schema.Types.String,
required: true,
}
}, {collection: 'users'});
There is the answer about transactions and collection creating -https://github.com/Automattic/mongoose/issues/6699
Actually, I use https://www.npmjs.com/package/db-migrate package to create collections and indexes before starting an app.

Next JS connection with Apollo and MongoDB

I am new to Next.js and using this example from Next.js https://github.com/zeit/next.js/tree/master/examples/api-routes-apollo-server-and-client.
However, the example is silent on MongoDB integration (also I could not find any other example for the same). I have been able to make database-connection but NOT able to use it in resolvers.
My Code
pages/api/graphql.js
import { ApolloServer } from 'apollo-server-micro'
import { schema } from '../../apollo/schema'
const MongoClient = require('mongodb').MongoClient;
let db
const apolloServer = new ApolloServer({
schema,
context: async () => {
if (!db) {
try {
const client = await MongoClient.connect(uri)
db = await client.db('dbName')
const post = await Posts.findOne()
console.log(post)
// It's working fine here
}
catch (e) {
// handle any errors
}
}
return { db }
},
})
export const config = {
api: {
bodyParser: false,
},
}
export default apolloServer.createHandler({ path: '/api/graphql' })
apollo/schema.js
import {makeExecutableSchema} from 'graphql-tools';
import {typeDefs} from './type-defs';
import {resolvers} from './resolvers';
export const schema = makeExecutableSchema({
typeDefs,
resolvers
});
apollo/resolvers.js
const Items = require('./connector').Items;
export const resolvers = {
Query: {
viewer(_parent, _args, _context, _info) {
//want to populate values here, using database connection
return { id: 1, name: 'John Smith', status: 'cached' }
},
...
}
}
I am stuck in the resolvers.js part. Don't know how to get the cached database connection inside resolvers.js. If I create a new database connection file, top-level await is not supported there, so how do I proceed?
If context is a function, whatever you return from the function will be available as the context parameter in your resolver. So if you're returning { db }, that's what your context parameter will be -- in other words, you can access it as context.db inside your resolver.